import Foundation
import GenAPI

public struct AlignedLyrics: Codable, Equatable {
    enum CodingKeys: String, CodingKey {
        case alignedWords = "aligned_words"
        case isStreamed = "is_streamed"
        case waveformData = "waveform_data"
        case alignedLyrics = "aligned_lyrics"
    }

    public let isStreamed: Bool
    public let alignedWords: [AlignedLyric]
    public let waveformData: [Float]
    public let alignedLyrics: [AlignedLyricLine]
}

extension AlignedLyrics {
    init(_ remote: Components.Schemas.AlignedLyricsV2Schema) {
        self.alignedWords = remote.aligned_words.compactMap {
            AlignedLyric(word: $0.word, startsAt: $0.start_s, endsAt: $0.end_s)
        }
        self.isStreamed = remote.is_streamed
        if let waveformData = remote.waveform_data {
            self.waveformData = waveformData.compactMap { Float(String(describing: $0)) }
        } else {
            self.waveformData = []
        }
        self.alignedLyrics = (remote.aligned_lyrics ?? []).map { AlignedLyricLine($0) }
    }

    init(_ remote: [GenAPI.AlignedLyricSchema]) {
        self.isStreamed = false
        self.waveformData = []
        self.alignedWords = remote.flatMap { lyricLine in
            lyricLine.words.map { word in
                AlignedLyric(word: word.text, startsAt: word.startS, endsAt: word.endS)
            }
        }
        self.alignedLyrics = remote.map { AlignedLyricLine($0) }
    }
}

public struct AlignedLyric: Codable, Equatable {
    enum CodingKeys: String, CodingKey {
        case word, startsAt = "start_s", endsAt = "end_s"
    }

    public let word: String
    public let startsAt: TimeInterval
    public let endsAt: TimeInterval

    public init(word: String, startsAt: TimeInterval, endsAt: TimeInterval) {
        self.word = word
        self.startsAt = startsAt
        self.endsAt = endsAt
    }
}

public struct AlignedLyricLine: Codable, Equatable {
    public let text: String
    public let startS: Double
    public let endS: Double
    public let section: String
    public let words: [WordOutput]

    init(_ remote: Components.Schemas.AlignedLyricSchema) {
        self.text = remote.text
        self.startS = remote.start_s
        self.endS = remote.end_s
        self.section = remote.section
        self.words = remote.words.map { WordOutput($0) }
    }

    init(_ remote: GenAPI.AlignedLyricSchema) {
        self.text = remote.text
        self.startS = remote.startS
        self.endS = remote.endS
        self.section = remote.section
        self.words = remote.words.map { WordOutput($0) }
    }
}

public struct WordOutput: Codable, Equatable {
    public let text: String
    public let startS: Double
    public let endS: Double

    init(_ remote: Components.Schemas.WordOutputSchema) {
        self.text = remote.text
        self.startS = remote.start_s
        self.endS = remote.end_s
    }

    init(_ remote: GenAPI.WordOutputSchema) {
        self.text = remote.text
        self.startS = remote.startS
        self.endS = remote.endS
    }
}

extension AlignedLyric {
    init?(_ remote: Components.Schemas.AlignedWordSchema?) {
        guard let remote = remote else { return nil }
        self.startsAt = remote.start_s
        self.endsAt = remote.end_s
        self.word = remote.word
    }

    init?(_ remote: Components.Schemas.AlignedLyric?) {
        guard let word = remote?.word, let start = remote?.start_s, let end = remote?.end_s else { return nil }
        self.startsAt = start
        self.endsAt = end
        self.word = word
    }
}

#if DEBUG
    public extension AlignedLyrics {
        static func mock() -> AlignedLyrics {
            AlignedLyrics(isStreamed: false, alignedWords: [], waveformData: [], alignedLyrics: [])
        }
    }
#endif
