//
//  CKModels.swift
//  SportsTime
//
//  CloudKit Record Type Definitions for Public Database
//

import Foundation
import CloudKit

// MARK: - Record Type Constants

enum CKRecordType {
    static let team = "Team"
    static let stadium = "Stadium"
    static let game = "Game"
    static let sport = "Sport"
    static let leagueStructure = "LeagueStructure"
    static let teamAlias = "TeamAlias"
    static let stadiumAlias = "StadiumAlias"
}

// MARK: - CKTeam

struct CKTeam {
    static let idKey = "teamId"
    static let canonicalIdKey = "canonicalId"
    static let nameKey = "name"
    static let abbreviationKey = "abbreviation"
    static let sportKey = "sport"
    static let cityKey = "city"
    static let stadiumRefKey = "stadiumRef"
    static let stadiumCanonicalIdKey = "stadiumCanonicalId"
    static let logoURLKey = "logoURL"
    static let primaryColorKey = "primaryColor"
    static let secondaryColorKey = "secondaryColor"

    let record: CKRecord

    init(record: CKRecord) {
        self.record = record
    }

    init(team: Team, stadiumRecordID: CKRecord.ID) {
        let record = CKRecord(recordType: CKRecordType.team)
        record[CKTeam.idKey] = team.id
        record[CKTeam.nameKey] = team.name
        record[CKTeam.abbreviationKey] = team.abbreviation
        record[CKTeam.sportKey] = team.sport.rawValue
        record[CKTeam.cityKey] = team.city
        record[CKTeam.stadiumRefKey] = CKRecord.Reference(recordID: stadiumRecordID, action: .none)
        record[CKTeam.logoURLKey] = team.logoURL?.absoluteString
        record[CKTeam.primaryColorKey] = team.primaryColor
        record[CKTeam.secondaryColorKey] = team.secondaryColor
        self.record = record
    }

    /// The canonical ID string from CloudKit (e.g., "team_nba_atl")
    var canonicalId: String? {
        record[CKTeam.canonicalIdKey] as? String
    }

    /// The stadium canonical ID string from CloudKit (e.g., "stadium_nba_state_farm_arena")
    var stadiumCanonicalId: String? {
        record[CKTeam.stadiumCanonicalIdKey] as? String
    }

    var team: Team? {
        // Use teamId field, or fall back to record name
        let id = (record[CKTeam.idKey] as? String) ?? record.recordID.recordName
        guard !id.isEmpty,
              let abbreviation = record[CKTeam.abbreviationKey] as? String,
              let sportRaw = record[CKTeam.sportKey] as? String,
              let sport = Sport(rawValue: sportRaw),
              let city = record[CKTeam.cityKey] as? String
        else { return nil }

        // Name defaults to abbreviation if not provided
        let name = record[CKTeam.nameKey] as? String ?? abbreviation

        // Stadium reference is optional - use placeholder string if not present
        let stadiumId: String
        if let stadiumRef = record[CKTeam.stadiumRefKey] as? CKRecord.Reference {
            stadiumId = stadiumRef.recordID.recordName
        } else {
            // Generate placeholder from team ID
            stadiumId = "stadium_placeholder_\(id)"
        }

        let logoURL = (record[CKTeam.logoURLKey] as? String).flatMap { URL(string: $0) }

        return Team(
            id: id,
            name: name,
            abbreviation: abbreviation,
            sport: sport,
            city: city,
            stadiumId: stadiumId,
            logoURL: logoURL,
            primaryColor: record[CKTeam.primaryColorKey] as? String,
            secondaryColor: record[CKTeam.secondaryColorKey] as? String
        )
    }
}

// MARK: - CKStadium

struct CKStadium {
    static let idKey = "stadiumId"
    static let canonicalIdKey = "canonicalId"
    static let nameKey = "name"
    static let cityKey = "city"
    static let stateKey = "state"
    static let locationKey = "location"
    static let capacityKey = "capacity"
    static let yearOpenedKey = "yearOpened"
    static let imageURLKey = "imageURL"
    static let sportKey = "sport"

    let record: CKRecord

    init(record: CKRecord) {
        self.record = record
    }

    init(stadium: Stadium) {
        let record = CKRecord(recordType: CKRecordType.stadium)
        record[CKStadium.idKey] = stadium.id
        record[CKStadium.nameKey] = stadium.name
        record[CKStadium.cityKey] = stadium.city
        record[CKStadium.stateKey] = stadium.state
        record[CKStadium.locationKey] = CLLocation(latitude: stadium.latitude, longitude: stadium.longitude)
        record[CKStadium.capacityKey] = stadium.capacity
        record[CKStadium.yearOpenedKey] = stadium.yearOpened
        record[CKStadium.imageURLKey] = stadium.imageURL?.absoluteString
        record[CKStadium.sportKey] = stadium.sport.rawValue
        self.record = record
    }

    /// The canonical ID string from CloudKit (e.g., "stadium_nba_state_farm_arena")
    var canonicalId: String? {
        record[CKStadium.canonicalIdKey] as? String
    }

    var stadium: Stadium? {
        // Use stadiumId field, or fall back to record name
        let id = (record[CKStadium.idKey] as? String) ?? record.recordID.recordName
        guard !id.isEmpty,
              let name = record[CKStadium.nameKey] as? String,
              let city = record[CKStadium.cityKey] as? String
        else { return nil }

        // These fields are optional in CloudKit
        let state = record[CKStadium.stateKey] as? String ?? ""
        let location = record[CKStadium.locationKey] as? CLLocation
        let capacity = record[CKStadium.capacityKey] as? Int ?? 0
        let imageURL = (record[CKStadium.imageURLKey] as? String).flatMap { URL(string: $0) }
        let sportRaw = record[CKStadium.sportKey] as? String ?? "MLB"
        let sport = Sport(rawValue: sportRaw) ?? .mlb

        return Stadium(
            id: id,
            name: name,
            city: city,
            state: state,
            latitude: location?.coordinate.latitude ?? 0,
            longitude: location?.coordinate.longitude ?? 0,
            capacity: capacity,
            sport: sport,
            yearOpened: record[CKStadium.yearOpenedKey] as? Int,
            imageURL: imageURL
        )
    }
}

// MARK: - CKGame

struct CKGame {
    static let idKey = "gameId"
    static let canonicalIdKey = "canonicalId"
    static let homeTeamRefKey = "homeTeamRef"
    static let awayTeamRefKey = "awayTeamRef"
    static let stadiumRefKey = "stadiumRef"
    static let homeTeamCanonicalIdKey = "homeTeamCanonicalId"
    static let awayTeamCanonicalIdKey = "awayTeamCanonicalId"
    static let stadiumCanonicalIdKey = "stadiumCanonicalId"
    static let dateTimeKey = "dateTime"
    static let sportKey = "sport"
    static let seasonKey = "season"
    static let isPlayoffKey = "isPlayoff"
    static let broadcastInfoKey = "broadcastInfo"

    let record: CKRecord

    init(record: CKRecord) {
        self.record = record
    }

    init(game: Game, homeTeamRecordID: CKRecord.ID, awayTeamRecordID: CKRecord.ID, stadiumRecordID: CKRecord.ID) {
        let record = CKRecord(recordType: CKRecordType.game)
        record[CKGame.idKey] = game.id
        record[CKGame.homeTeamRefKey] = CKRecord.Reference(recordID: homeTeamRecordID, action: .none)
        record[CKGame.awayTeamRefKey] = CKRecord.Reference(recordID: awayTeamRecordID, action: .none)
        record[CKGame.stadiumRefKey] = CKRecord.Reference(recordID: stadiumRecordID, action: .none)
        record[CKGame.dateTimeKey] = game.dateTime
        record[CKGame.sportKey] = game.sport.rawValue
        record[CKGame.seasonKey] = game.season
        record[CKGame.isPlayoffKey] = game.isPlayoff ? 1 : 0
        record[CKGame.broadcastInfoKey] = game.broadcastInfo
        self.record = record
    }

    /// The canonical ID string from CloudKit (e.g., "game_nba_202526_20251021_hou_okc")
    var canonicalId: String? {
        record[CKGame.canonicalIdKey] as? String
    }

    /// The home team canonical ID string from CloudKit (e.g., "team_nba_okc")
    var homeTeamCanonicalId: String? {
        record[CKGame.homeTeamCanonicalIdKey] as? String
    }

    /// The away team canonical ID string from CloudKit (e.g., "team_nba_hou")
    var awayTeamCanonicalId: String? {
        record[CKGame.awayTeamCanonicalIdKey] as? String
    }

    /// The stadium canonical ID string from CloudKit (e.g., "stadium_nba_paycom_center")
    var stadiumCanonicalId: String? {
        record[CKGame.stadiumCanonicalIdKey] as? String
    }

    func game(homeTeamId: String, awayTeamId: String, stadiumId: String) -> Game? {
        let id = (record[CKGame.idKey] as? String) ?? record.recordID.recordName
        guard !id.isEmpty,
              let dateTime = record[CKGame.dateTimeKey] as? Date,
              let sportRaw = record[CKGame.sportKey] as? String,
              let sport = Sport(rawValue: sportRaw),
              let season = record[CKGame.seasonKey] as? String
        else { return nil }

        return Game(
            id: id,
            homeTeamId: homeTeamId,
            awayTeamId: awayTeamId,
            stadiumId: stadiumId,
            dateTime: dateTime,
            sport: sport,
            season: season,
            isPlayoff: (record[CKGame.isPlayoffKey] as? Int) == 1,
            broadcastInfo: record[CKGame.broadcastInfoKey] as? String
        )
    }
}

// MARK: - CKLeagueStructure

struct CKLeagueStructure {
    static let idKey = "structureId"
    static let sportKey = "sport"
    static let typeKey = "type"
    static let nameKey = "name"
    static let abbreviationKey = "abbreviation"
    static let parentIdKey = "parentId"
    static let displayOrderKey = "displayOrder"
    static let schemaVersionKey = "schemaVersion"
    static let lastModifiedKey = "lastModified"

    let record: CKRecord

    init(record: CKRecord) {
        self.record = record
    }

    init(model: LeagueStructureModel) {
        let record = CKRecord(recordType: CKRecordType.leagueStructure, recordID: CKRecord.ID(recordName: model.id))
        record[CKLeagueStructure.idKey] = model.id
        record[CKLeagueStructure.sportKey] = model.sport
        record[CKLeagueStructure.typeKey] = model.structureTypeRaw
        record[CKLeagueStructure.nameKey] = model.name
        record[CKLeagueStructure.abbreviationKey] = model.abbreviation
        record[CKLeagueStructure.parentIdKey] = model.parentId
        record[CKLeagueStructure.displayOrderKey] = model.displayOrder
        record[CKLeagueStructure.schemaVersionKey] = model.schemaVersion
        record[CKLeagueStructure.lastModifiedKey] = model.lastModified
        self.record = record
    }

    /// Convert to SwiftData model for local storage
    func toModel() -> LeagueStructureModel? {
        guard let id = record[CKLeagueStructure.idKey] as? String,
              let sport = record[CKLeagueStructure.sportKey] as? String,
              let typeRaw = record[CKLeagueStructure.typeKey] as? String,
              let structureType = LeagueStructureType(rawValue: typeRaw),
              let name = record[CKLeagueStructure.nameKey] as? String
        else { return nil }

        let abbreviation = record[CKLeagueStructure.abbreviationKey] as? String
        let parentId = record[CKLeagueStructure.parentIdKey] as? String
        let displayOrder = record[CKLeagueStructure.displayOrderKey] as? Int ?? 0
        let schemaVersion = record[CKLeagueStructure.schemaVersionKey] as? Int ?? SchemaVersion.current
        let lastModified = record[CKLeagueStructure.lastModifiedKey] as? Date ?? record.modificationDate ?? Date()

        return LeagueStructureModel(
            id: id,
            sport: sport,
            structureType: structureType,
            name: name,
            abbreviation: abbreviation,
            parentId: parentId,
            displayOrder: displayOrder,
            schemaVersion: schemaVersion,
            lastModified: lastModified
        )
    }
}

// MARK: - CKStadiumAlias

struct CKStadiumAlias {
    static let aliasNameKey = "aliasName"
    static let stadiumCanonicalIdKey = "stadiumCanonicalId"
    static let validFromKey = "validFrom"
    static let validUntilKey = "validUntil"
    static let schemaVersionKey = "schemaVersion"
    static let lastModifiedKey = "lastModified"

    let record: CKRecord

    init(record: CKRecord) {
        self.record = record
    }

    init(model: StadiumAlias) {
        let record = CKRecord(recordType: CKRecordType.stadiumAlias, recordID: CKRecord.ID(recordName: model.aliasName))
        record[CKStadiumAlias.aliasNameKey] = model.aliasName
        record[CKStadiumAlias.stadiumCanonicalIdKey] = model.stadiumCanonicalId
        record[CKStadiumAlias.validFromKey] = model.validFrom
        record[CKStadiumAlias.validUntilKey] = model.validUntil
        record[CKStadiumAlias.schemaVersionKey] = model.schemaVersion
        record[CKStadiumAlias.lastModifiedKey] = model.lastModified
        self.record = record
    }

    /// Convert to SwiftData model for local storage
    func toModel() -> StadiumAlias? {
        guard let aliasName = record[CKStadiumAlias.aliasNameKey] as? String,
              let stadiumCanonicalId = record[CKStadiumAlias.stadiumCanonicalIdKey] as? String
        else { return nil }

        let validFrom = record[CKStadiumAlias.validFromKey] as? Date
        let validUntil = record[CKStadiumAlias.validUntilKey] as? Date
        let schemaVersion = record[CKStadiumAlias.schemaVersionKey] as? Int ?? SchemaVersion.current
        let lastModified = record[CKStadiumAlias.lastModifiedKey] as? Date ?? record.modificationDate ?? Date()

        return StadiumAlias(
            aliasName: aliasName,
            stadiumCanonicalId: stadiumCanonicalId,
            validFrom: validFrom,
            validUntil: validUntil,
            schemaVersion: schemaVersion,
            lastModified: lastModified
        )
    }
}

// MARK: - CKTeamAlias

struct CKTeamAlias {
    static let idKey = "aliasId"
    static let teamCanonicalIdKey = "teamCanonicalId"
    static let aliasTypeKey = "aliasType"
    static let aliasValueKey = "aliasValue"
    static let validFromKey = "validFrom"
    static let validUntilKey = "validUntil"
    static let schemaVersionKey = "schemaVersion"
    static let lastModifiedKey = "lastModified"

    let record: CKRecord

    init(record: CKRecord) {
        self.record = record
    }

    init(model: TeamAlias) {
        let record = CKRecord(recordType: CKRecordType.teamAlias, recordID: CKRecord.ID(recordName: model.id))
        record[CKTeamAlias.idKey] = model.id
        record[CKTeamAlias.teamCanonicalIdKey] = model.teamCanonicalId
        record[CKTeamAlias.aliasTypeKey] = model.aliasTypeRaw
        record[CKTeamAlias.aliasValueKey] = model.aliasValue
        record[CKTeamAlias.validFromKey] = model.validFrom
        record[CKTeamAlias.validUntilKey] = model.validUntil
        record[CKTeamAlias.schemaVersionKey] = model.schemaVersion
        record[CKTeamAlias.lastModifiedKey] = model.lastModified
        self.record = record
    }

    /// Convert to SwiftData model for local storage
    func toModel() -> TeamAlias? {
        guard let id = record[CKTeamAlias.idKey] as? String,
              let teamCanonicalId = record[CKTeamAlias.teamCanonicalIdKey] as? String,
              let aliasTypeRaw = record[CKTeamAlias.aliasTypeKey] as? String,
              let aliasType = TeamAliasType(rawValue: aliasTypeRaw),
              let aliasValue = record[CKTeamAlias.aliasValueKey] as? String
        else { return nil }

        let validFrom = record[CKTeamAlias.validFromKey] as? Date
        let validUntil = record[CKTeamAlias.validUntilKey] as? Date
        let schemaVersion = record[CKTeamAlias.schemaVersionKey] as? Int ?? SchemaVersion.current
        let lastModified = record[CKTeamAlias.lastModifiedKey] as? Date ?? record.modificationDate ?? Date()

        return TeamAlias(
            id: id,
            teamCanonicalId: teamCanonicalId,
            aliasType: aliasType,
            aliasValue: aliasValue,
            validFrom: validFrom,
            validUntil: validUntil,
            schemaVersion: schemaVersion,
            lastModified: lastModified
        )
    }
}
