import Foundation
import GRDB

// `nonisolated` opts this struct out of the project-wide `default-isolation = MainActor`
// setting. Without it, the compiler tries to infer MainActor isolation and hits a circular
// reference when synthesising Equatable/Hashable conformances.
nonisolated struct Track: Codable, Identifiable, Equatable, Hashable, Sendable {
    var id: Int64?
    var fileURL: String
    var title: String
    var artist: String
    var albumArtist: String
    var album: String
    var genre: String
    var year: Int?
    var trackNumber: Int?
    var discNumber: Int?
    var duration: Double
    var bpm: Int?
    var composer: String
    var fileFormat: String
    var bitrate: Int?
    var sampleRate: Int?
    var fileSize: Int64
    var playCount: Int
    var lastPlayedAt: Date?
    var rating: Int
    var dateAdded: Date
    var dateModified: Date
    var fileHash: String

    static func computeHash(fileSize: Int64, modificationDate: Date) -> String {
        "\(fileSize)_\(Int(modificationDate.timeIntervalSince1970))"
    }
}

// Also `nonisolated` so the GRDB protocol conformances (FetchableRecord,
// MutablePersistableRecord) are not inferred as MainActor-isolated, which
// would prevent using them in Sendable contexts.
nonisolated extension Track: FetchableRecord, MutablePersistableRecord {
    static let databaseTableName = "tracks"

    mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}

#if DEBUG
extension Track {
    static func fixture(
        id: Int64? = nil,
        fileURL: String = "/tmp/test.mp3",
        title: String = "Test Song",
        artist: String = "Test Artist",
        albumArtist: String = "Test Artist",
        album: String = "Test Album",
        genre: String = "Rock",
        year: Int? = 2024,
        trackNumber: Int? = 1,
        discNumber: Int? = 1,
        duration: Double = 210.0,
        bpm: Int? = 120,
        composer: String = "Test Composer",
        fileFormat: String = "mp3",
        bitrate: Int? = 320,
        sampleRate: Int? = 44100,
        fileSize: Int64 = 5_000_000,
        playCount: Int = 0,
        lastPlayedAt: Date? = nil,
        rating: Int = 0,
        dateAdded: Date = Date(),
        dateModified: Date = Date(),
        fileHash: String = "5000000_1700000000"
    ) -> Track {
        Track(
            id: id, fileURL: fileURL, title: title, artist: artist,
            albumArtist: albumArtist, album: album, genre: genre, year: year,
            trackNumber: trackNumber, discNumber: discNumber, duration: duration,
            bpm: bpm, composer: composer, fileFormat: fileFormat, bitrate: bitrate,
            sampleRate: sampleRate, fileSize: fileSize,
            playCount: playCount, lastPlayedAt: lastPlayedAt, rating: rating,
            dateAdded: dateAdded, dateModified: dateModified, fileHash: fileHash
        )
    }
}
#endif
