import ComposableArchitecture
import Foundation
import GenAPI

public struct ClipLineage: Equatable {
    public var root: Clip
    public var children: [ChildClip]

    init(_ remote: GenAPI.ChildClipsSchema) throws {
        guard let root = remote.rootClips.first else {
            throw ClipLineageError.missingRootClip
        }

        self.root = try .init(root)

        children = try remote.childClips.compactMap { childClip in
            try .init(childClip)
        }
    }
}

/*
 Contains the clip but also a couple of helpful properties: extendOffset and totalDuration.
 `extendOffset` is the concatenated extension timestamp from all clips in this clip's lineage.
 This makes sure we can easily tell the user the timestamp in reference to the original clip,
 without doing any recursive math on the client. Similar concept applies for `totalDuration`:
 it's the total duration of full song with all the extensions selected, if the user were to
 do so.
 */
public struct ChildClip: Equatable {
    public var clip: Clip
    public var relationship: String
    public var extendOffset: Double?
    public var totalDuration: Double?
    public var index: Int

    // Make this initializer private to avoid confusion
    init(_ remote: GenAPI.ChildClipSchema) throws {
        self.clip = try .init(remote.clip)
        self.relationship = remote.relationship
        self.extendOffset = remote.extendOffset
        self.totalDuration = remote.totalDuration
        self.index = remote.index + 1
    }

    // Root clip convenience initializer since
    // it doesn't come in this structure
    public init(
        clip: Clip,
        extendOffset: Double = 0,
        totalDuration: Double? = nil,
        index: Int = 0
    ) {
        self.clip = clip
        self.relationship = "EX" // Note: Setting this to "EX" in every case is outdated, but as of right now we still don't have a use for this.
        self.extendOffset = extendOffset
        self.totalDuration = totalDuration ?? clip.duration
        self.index = index
    }
}

public enum ClipLineageError: Error {
    case missingRootClip
}

/*
 Interestingly, `ParentClipSchema` doesn't expose the `GeneratedClipSchema` of the parent
 */
public struct ParentClip: Equatable, Identifiable {
    public var id: ClipID
    public var imageUrl: String?
    public var isPublic: Bool
    public var title: String
    public var userAvatarImageUrl: String?
    public var userDisplayName: String?
    public var userHandle: String

    public init?(_ remote: GenAPI.ParentClipSchema) throws {
        /// These fields are optional in `ParentClipSchema` but cannot be optional in our feature code.
        /// Let's enforce these conversions on our end until `ParentClipSchema` gets updated
        guard let clipId = try? ClipID(remote) else { return nil }
        guard let title = remote.title else { return nil }
        guard let userHandle = remote.userHandle else { return nil }

        self.id = clipId
        self.imageUrl = remote.imageUrl
        self.isPublic = remote.isPublic
        self.title = title
        self.userAvatarImageUrl = remote.userAvatarImageUrl
        self.userDisplayName = remote.userDisplayName
        self.userHandle = userHandle
    }
}

public extension ClipID {
    init?(_ remote: GenAPI.ParentClipSchema) throws {
        guard let uuid = remote.id?.uuidString else { return nil }
        remoteId = uuid.lowercased()
    }
}

public extension ParentClip {
    init(id: String, imageUrl: String, isPublic: Bool, title: String, userAvatarImageUrl: String, userDisplayName: String, userHandle: String) {
        self.id = .init(remoteId: id)
        self.imageUrl = imageUrl
        self.isPublic = isPublic
        self.title = title
        self.userAvatarImageUrl = userAvatarImageUrl
        self.userDisplayName = userDisplayName
        self.userHandle = userHandle
    }

    static let mock: Self = .init(
        id: "68c124b8-d40b-4e3d-9926-1c17812fda12",
        imageUrl: "https://cdn2.suno.ai/image_68c124b8-d40b-4e3d-9926-1c17812fda12.jpeg",
        isPublic: true,
        title: "Skeleton In My Closet",
        userAvatarImageUrl: "https://cdn1.suno.ai/defaultPink.jpg",
        userDisplayName: "JBroT",
        userHandle: "intensereview642"
    )
}
