import Foundation

// MARK: - Song

/// A complete multipart song with metadata and all parts.
struct Song: Equatable {
    let title: String
    let timeSignature: TimeSignature
    let keySignature: KeySignature
    let defaultTempo: Int           // BPM from the file
    let parts: [Part]               // Ordered list of parts

    /// Total number of measures in the song (max across all parts)
    var totalMeasures: Int {
        return parts.map { $0.measures.count }.max() ?? 0
    }

    /// Part names in order
    var partNames: [String] {
        return parts.map { $0.name }
    }

    /// Lookup a part by name (case-insensitive)
    func part(named name: String) -> Part? {
        return parts.first { $0.name.lowercased() == name.lowercased() }
    }

    /// Total duration of the song in seconds at a given BPM
    func totalSeconds(atBPM bpm: Double) -> Double {
        let totalBeats = timeSignature.quarterNoteBeatsPerMeasure * Double(totalMeasures)
        return totalBeats * (60.0 / bpm)
    }

    /// Duration of a range of measures in seconds at a given BPM
    func secondsForMeasures(from start: Int, to end: Int, atBPM bpm: Double) -> Double {
        let measureCount = max(0, end - start + 1)
        let totalBeats = timeSignature.quarterNoteBeatsPerMeasure * Double(measureCount)
        return totalBeats * (60.0 / bpm)
    }

    /// Beat offset for a given measure index
    func beatOffset(forMeasure index: Int) -> Double {
        return timeSignature.quarterNoteBeatsPerMeasure * Double(index)
    }
}

extension Song: CustomStringConvertible {
    var description: String {
        let partDesc = parts.map { "  \($0)" }.joined(separator: "\n")
        return """
        "\(title)" (\(timeSignature), \(keySignature), \(defaultTempo) bpm)
        \(parts.count) parts, \(totalMeasures) measures:
        \(partDesc)
        """
    }
}
