import BackendEnvironmentClient
import Foundation
import GenAPI
import Localization

public struct Playlist: Identifiable, Equatable, Hashable {
    public var id: String
    public var clips: [Clip]
    public var name: String
    public var description: String
    public var totalResults: Int
    public var imageUrl: String?
    public var isTrashed: Bool
    public var isPublic: Bool
    public var isOwned: Bool
    public var userDisplayName: String?
    public var userHandle: String?
    public var userAvatarImageUrl: String?
    public var playCount: Int?
    public var upvoteCount: Int?
    public var isAdded: Bool?

    public var shareURL: URL {
        let baseUrl = BackendEnvironmentProvider.currentConfiguration().webEndpointHost
        return URL(string: "https://\(baseUrl)/playlist/\(id)")!
    }

    public var isLikedPlaylist: Bool { id.lowercased() == "liked" }

    public func contains(clip: Clip) -> Bool {
        if isLikedPlaylist {
            return clip.isLiked
        }

        return clips.contains(where: { $0.id.global == clip.id.global })
    }
}

extension Playlist {
    init<Remote: Playlistable>(_ remote: Remote) throws {
        id = try remote.decodeRequired(\.id.string)
        clips = try remote.playlistClips.map(Clip.init)
        name = {
            guard let title = remote.name?.trimmingCharacters(in: .whitespacesAndNewlines),
                  !title.isEmpty
            else { return L10n.APIClient.untitled }

            return title
        }()
        description = remote.description ?? ""
        totalResults = remote.numTotalResults
        imageUrl = remote.imageUrl ?? clips.first?.imageUrl
        isTrashed = remote.isTrashed
        isPublic = remote.isPublic
        isOwned = remote.isOwned
        userDisplayName = remote.userDisplayName
        userHandle = remote.userHandle
        userAvatarImageUrl = remote.userAvatarImageUrl
        playCount = remote.playCount
        upvoteCount = remote.upvoteCount
    }

    init(_ source: GenAPI.PlaylistItemSchema) throws {
        id = try source.decodeRequired(\.id.string)
        clips = try source.playlistClips.map { try Clip($0.clip) }
        name = {
            guard let title = source.name?.trimmingCharacters(in: .whitespacesAndNewlines),
                  !title.isEmpty
            else { return L10n.APIClient.untitled }

            return title
        }()
        description = source.description ?? ""
        totalResults = source.numTotalResults
        imageUrl = source.imageUrl ?? clips.first?.imageUrl
        isTrashed = source.isTrashed
        isPublic = source.isPublic
        isOwned = source.isOwned
        userDisplayName = source.userDisplayName
        userHandle = source.userHandle
        userAvatarImageUrl = source.userAvatarImageUrl
        playCount = source.playCount
        upvoteCount = source.upvoteCount
    }

    init(_ source: GenAPI.PlaylistMetadataWithTargetClipStatusSchema) throws {
        id = try source.decodeRequired(\.id.string)
        clips = try source.playlistClips.map { try Clip($0.clip) }
        name = {
            guard let title = source.name?.trimmingCharacters(in: .whitespacesAndNewlines),
                  !title.isEmpty
            else { return L10n.APIClient.untitled }

            return title
        }()
        description = source.description ?? ""
        totalResults = source.numTotalResults
        imageUrl = source.imageUrl ?? clips.first?.imageUrl
        isTrashed = source.isTrashed
        isPublic = source.isPublic
        isOwned = source.isOwned
        userDisplayName = source.userDisplayName
        userHandle = source.userHandle
        userAvatarImageUrl = source.userAvatarImageUrl
        playCount = source.playCount
        upvoteCount = source.upvoteCount
        isAdded = source.isClipAdded
    }
}

public extension Playlist {
    static var liked: Self {
        .init(
            id: "liked",
            clips: [],
            name: "Liked songs",
            description: "",
            totalResults: 0,
            imageUrl: "",
            isTrashed: false,
            isPublic: false,
            isOwned: true,
            userDisplayName: "",
            userHandle: "",
            userAvatarImageUrl: nil,
            playCount: 0,
            upvoteCount: 0
        )
    }

    static var empty: Self {
        .init(
            id: "",
            clips: [],
            name: "",
            description: "",
            totalResults: 0,
            imageUrl: "",
            isTrashed: false,
            isPublic: false,
            isOwned: true,
            userDisplayName: "",
            userHandle: "",
            userAvatarImageUrl: nil,
            playCount: 0,
            upvoteCount: 0
        )
    }
}
