//
//  BootstrapService.swift
//  SportsTime
//
//  Bootstraps canonical data from bundled JSON files into SwiftData.
//  Runs once on first launch, then relies on CloudKit for updates.
//

import Foundation
import SwiftData
import CryptoKit

actor BootstrapService {

    // MARK: - Errors

    enum BootstrapError: Error, LocalizedError {
        case bundledResourceNotFound(String)
        case jsonDecodingFailed(String, Error)
        case saveFailed(Error)

        var errorDescription: String? {
            switch self {
            case .bundledResourceNotFound(let resource):
                return "Bundled resource not found: \(resource)"
            case .jsonDecodingFailed(let resource, let error):
                return "Failed to decode \(resource): \(error.localizedDescription)"
            case .saveFailed(let error):
                return "Failed to save bootstrap data: \(error.localizedDescription)"
            }
        }
    }

    // MARK: - JSON Models (match bundled JSON structure)

    // MARK: - Canonical JSON Models (from canonicalization pipeline)

    private struct JSONCanonicalStadium: Codable {
        let canonical_id: String
        let name: String
        let city: String
        let state: String
        let latitude: Double
        let longitude: Double
        let capacity: Int
        let sport: String
        let primary_team_abbrevs: [String]
        let year_opened: Int?
    }

    private struct JSONCanonicalTeam: Codable {
        let canonical_id: String
        let name: String
        let abbreviation: String
        let sport: String
        let city: String
        let stadium_canonical_id: String
        let conference_id: String?
        let division_id: String?
        let primary_color: String?
        let secondary_color: String?
    }

    private struct JSONCanonicalGame: Codable {
        let canonical_id: String
        let sport: String
        let season: String
        let date: String
        let time: String?
        let home_team_canonical_id: String
        let away_team_canonical_id: String
        let stadium_canonical_id: String
        let is_playoff: Bool
        let broadcast: String?
    }

    private struct JSONStadiumAlias: Codable {
        let alias_name: String
        let stadium_canonical_id: String
        let valid_from: String?
        let valid_until: String?
    }

    // MARK: - Legacy JSON Models (for backward compatibility)

    private struct JSONStadium: Codable {
        let id: String
        let name: String
        let city: String
        let state: String
        let latitude: Double
        let longitude: Double
        let capacity: Int
        let sport: String
        let team_abbrevs: [String]
        let source: String
        let year_opened: Int?
    }

    private struct JSONGame: Codable {
        let id: String
        let sport: String
        let season: String
        let date: String
        let time: String?
        let home_team: String
        let away_team: String
        let home_team_abbrev: String
        let away_team_abbrev: String
        let venue: String
        let source: String
        let is_playoff: Bool
        let broadcast: String?
    }

    private struct JSONLeagueStructure: Codable {
        let id: String
        let sport: String
        let type: String  // "conference", "division", "league"
        let name: String
        let abbreviation: String?
        let parent_id: String?
        let display_order: Int
    }

    private struct JSONTeamAlias: Codable {
        let id: String
        let team_canonical_id: String
        let alias_type: String  // "abbreviation", "name", "city"
        let alias_value: String
        let valid_from: String?
        let valid_until: String?
    }

    // MARK: - Public Methods

    /// Bootstrap canonical data from bundled JSON if not already done.
    /// This is the main entry point called at app launch.
    ///
    /// Prefers new canonical format files (*_canonical.json) from the pipeline,
    /// falls back to legacy format for backward compatibility.
    @MainActor
    func bootstrapIfNeeded(context: ModelContext) async throws {
        let syncState = SyncState.current(in: context)

        // Skip if already bootstrapped
        guard !syncState.bootstrapCompleted else {
            return
        }

        // Bootstrap in dependency order:
        // 1. Stadiums (no dependencies)
        // 2. Stadium aliases (depends on stadiums)
        // 3. League structure (no dependencies)
        // 4. Teams (depends on stadiums)
        // 5. Team aliases (depends on teams)
        // 6. Games (depends on teams + stadiums)

        try await bootstrapStadiums(context: context)
        try await bootstrapStadiumAliases(context: context)
        try await bootstrapLeagueStructure(context: context)
        try await bootstrapTeams(context: context)
        try await bootstrapTeamAliases(context: context)
        try await bootstrapGames(context: context)

        // Mark bootstrap complete
        syncState.bootstrapCompleted = true
        syncState.bundledSchemaVersion = SchemaVersion.current
        syncState.lastBootstrap = Date()

        do {
            try context.save()
        } catch {
            throw BootstrapError.saveFailed(error)
        }
    }

    // MARK: - Bootstrap Steps

    @MainActor
    private func bootstrapStadiums(context: ModelContext) async throws {
        // Try canonical format first, fall back to legacy
        if let url = Bundle.main.url(forResource: "stadiums_canonical", withExtension: "json") {
            try await bootstrapStadiumsCanonical(url: url, context: context)
        } else if let url = Bundle.main.url(forResource: "stadiums", withExtension: "json") {
            try await bootstrapStadiumsLegacy(url: url, context: context)
        } else {
            throw BootstrapError.bundledResourceNotFound("stadiums_canonical.json or stadiums.json")
        }
    }

    @MainActor
    private func bootstrapStadiumsCanonical(url: URL, context: ModelContext) async throws {
        let data: Data
        let stadiums: [JSONCanonicalStadium]

        do {
            data = try Data(contentsOf: url)
            stadiums = try JSONDecoder().decode([JSONCanonicalStadium].self, from: data)
        } catch {
            throw BootstrapError.jsonDecodingFailed("stadiums_canonical.json", error)
        }

        for jsonStadium in stadiums {
            let canonical = CanonicalStadium(
                canonicalId: jsonStadium.canonical_id,
                schemaVersion: SchemaVersion.current,
                lastModified: BundledDataTimestamp.stadiums,
                source: .bundled,
                name: jsonStadium.name,
                city: jsonStadium.city,
                state: jsonStadium.state.isEmpty ? stateFromCity(jsonStadium.city) : jsonStadium.state,
                latitude: jsonStadium.latitude,
                longitude: jsonStadium.longitude,
                capacity: jsonStadium.capacity,
                yearOpened: jsonStadium.year_opened,
                sport: jsonStadium.sport
            )
            context.insert(canonical)
        }
    }

    @MainActor
    private func bootstrapStadiumsLegacy(url: URL, context: ModelContext) async throws {
        let data: Data
        let stadiums: [JSONStadium]

        do {
            data = try Data(contentsOf: url)
            stadiums = try JSONDecoder().decode([JSONStadium].self, from: data)
        } catch {
            throw BootstrapError.jsonDecodingFailed("stadiums.json", error)
        }

        for jsonStadium in stadiums {
            let canonical = CanonicalStadium(
                canonicalId: jsonStadium.id,
                schemaVersion: SchemaVersion.current,
                lastModified: BundledDataTimestamp.stadiums,
                source: .bundled,
                name: jsonStadium.name,
                city: jsonStadium.city,
                state: jsonStadium.state.isEmpty ? stateFromCity(jsonStadium.city) : jsonStadium.state,
                latitude: jsonStadium.latitude,
                longitude: jsonStadium.longitude,
                capacity: jsonStadium.capacity,
                yearOpened: jsonStadium.year_opened,
                sport: jsonStadium.sport
            )
            context.insert(canonical)

            // Legacy format: create stadium alias for the current name
            let alias = StadiumAlias(
                aliasName: jsonStadium.name,
                stadiumCanonicalId: jsonStadium.id,
                schemaVersion: SchemaVersion.current,
                lastModified: BundledDataTimestamp.stadiums
            )
            alias.stadium = canonical
            context.insert(alias)
        }
    }

    @MainActor
    private func bootstrapStadiumAliases(context: ModelContext) async throws {
        // Stadium aliases are loaded from stadium_aliases.json (from canonical pipeline)
        guard let url = Bundle.main.url(forResource: "stadium_aliases", withExtension: "json") else {
            // Aliases are optional - legacy format creates them inline
            return
        }

        let data: Data
        let aliases: [JSONStadiumAlias]

        do {
            data = try Data(contentsOf: url)
            aliases = try JSONDecoder().decode([JSONStadiumAlias].self, from: data)
        } catch {
            throw BootstrapError.jsonDecodingFailed("stadium_aliases.json", error)
        }

        // Build stadium lookup
        let stadiumDescriptor = FetchDescriptor<CanonicalStadium>()
        let stadiums = (try? context.fetch(stadiumDescriptor)) ?? []
        let stadiumsByCanonicalId = Dictionary(uniqueKeysWithValues: stadiums.map { ($0.canonicalId, $0) })

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"

        for jsonAlias in aliases {
            let alias = StadiumAlias(
                aliasName: jsonAlias.alias_name,
                stadiumCanonicalId: jsonAlias.stadium_canonical_id,
                validFrom: jsonAlias.valid_from.flatMap { dateFormatter.date(from: $0) },
                validUntil: jsonAlias.valid_until.flatMap { dateFormatter.date(from: $0) },
                schemaVersion: SchemaVersion.current,
                lastModified: BundledDataTimestamp.stadiums
            )

            // Link to stadium if found
            if let stadium = stadiumsByCanonicalId[jsonAlias.stadium_canonical_id] {
                alias.stadium = stadium
            }

            context.insert(alias)
        }
    }

    @MainActor
    private func bootstrapLeagueStructure(context: ModelContext) async throws {
        // Load league structure if file exists
        guard let url = Bundle.main.url(forResource: "league_structure", withExtension: "json") else {
            // League structure is optional for MVP - create basic structure from known sports
            createDefaultLeagueStructure(context: context)
            return
        }

        let data: Data
        let structures: [JSONLeagueStructure]

        do {
            data = try Data(contentsOf: url)
            structures = try JSONDecoder().decode([JSONLeagueStructure].self, from: data)
        } catch {
            throw BootstrapError.jsonDecodingFailed("league_structure.json", error)
        }

        for structure in structures {
            let structureType: LeagueStructureType
            switch structure.type.lowercased() {
            case "conference": structureType = .conference
            case "division": structureType = .division
            case "league": structureType = .league
            default: structureType = .division
            }

            let model = LeagueStructureModel(
                id: structure.id,
                sport: structure.sport,
                structureType: structureType,
                name: structure.name,
                abbreviation: structure.abbreviation,
                parentId: structure.parent_id,
                displayOrder: structure.display_order,
                schemaVersion: SchemaVersion.current,
                lastModified: BundledDataTimestamp.leagueStructure
            )
            context.insert(model)
        }
    }

    @MainActor
    private func bootstrapTeams(context: ModelContext) async throws {
        // Try canonical format first, fall back to legacy extraction from games
        if let url = Bundle.main.url(forResource: "teams_canonical", withExtension: "json") {
            try await bootstrapTeamsCanonical(url: url, context: context)
        } else {
            // Legacy: Teams will be extracted from games during bootstrapGames
            // This path is deprecated but maintained for backward compatibility
        }
    }

    @MainActor
    private func bootstrapTeamsCanonical(url: URL, context: ModelContext) async throws {
        let data: Data
        let teams: [JSONCanonicalTeam]

        do {
            data = try Data(contentsOf: url)
            teams = try JSONDecoder().decode([JSONCanonicalTeam].self, from: data)
        } catch {
            throw BootstrapError.jsonDecodingFailed("teams_canonical.json", error)
        }

        for jsonTeam in teams {
            let team = CanonicalTeam(
                canonicalId: jsonTeam.canonical_id,
                schemaVersion: SchemaVersion.current,
                lastModified: BundledDataTimestamp.games,
                source: .bundled,
                name: jsonTeam.name,
                abbreviation: jsonTeam.abbreviation,
                sport: jsonTeam.sport,
                city: jsonTeam.city,
                stadiumCanonicalId: jsonTeam.stadium_canonical_id,
                conferenceId: jsonTeam.conference_id,
                divisionId: jsonTeam.division_id
            )
            context.insert(team)
        }
    }

    @MainActor
    private func bootstrapGames(context: ModelContext) async throws {
        // Try canonical format first, fall back to legacy
        if let url = Bundle.main.url(forResource: "games_canonical", withExtension: "json") {
            try await bootstrapGamesCanonical(url: url, context: context)
        } else if let url = Bundle.main.url(forResource: "games", withExtension: "json") {
            try await bootstrapGamesLegacy(url: url, context: context)
        } else {
            throw BootstrapError.bundledResourceNotFound("games_canonical.json or games.json")
        }
    }

    @MainActor
    private func bootstrapGamesCanonical(url: URL, context: ModelContext) async throws {
        let data: Data
        let games: [JSONCanonicalGame]

        do {
            data = try Data(contentsOf: url)
            games = try JSONDecoder().decode([JSONCanonicalGame].self, from: data)
        } catch {
            throw BootstrapError.jsonDecodingFailed("games_canonical.json", error)
        }

        var seenGameIds = Set<String>()

        for jsonGame in games {
            // Deduplicate
            guard !seenGameIds.contains(jsonGame.canonical_id) else { continue }
            seenGameIds.insert(jsonGame.canonical_id)

            guard let dateTime = parseDateTime(date: jsonGame.date, time: jsonGame.time ?? "7:00p") else {
                continue
            }

            let game = CanonicalGame(
                canonicalId: jsonGame.canonical_id,
                schemaVersion: SchemaVersion.current,
                lastModified: BundledDataTimestamp.games,
                source: .bundled,
                homeTeamCanonicalId: jsonGame.home_team_canonical_id,
                awayTeamCanonicalId: jsonGame.away_team_canonical_id,
                stadiumCanonicalId: jsonGame.stadium_canonical_id,
                dateTime: dateTime,
                sport: jsonGame.sport,
                season: jsonGame.season,
                isPlayoff: jsonGame.is_playoff,
                broadcastInfo: jsonGame.broadcast
            )
            context.insert(game)
        }
    }

    @MainActor
    private func bootstrapGamesLegacy(url: URL, context: ModelContext) async throws {
        let data: Data
        let games: [JSONGame]

        do {
            data = try Data(contentsOf: url)
            games = try JSONDecoder().decode([JSONGame].self, from: data)
        } catch {
            throw BootstrapError.jsonDecodingFailed("games.json", error)
        }

        // Build stadium lookup for legacy venue matching
        let stadiumDescriptor = FetchDescriptor<CanonicalStadium>()
        let canonicalStadiums = (try? context.fetch(stadiumDescriptor)) ?? []
        var stadiumsByVenue: [String: CanonicalStadium] = [:]
        for stadium in canonicalStadiums {
            stadiumsByVenue[stadium.name.lowercased()] = stadium
        }

        // Check if teams already exist (from teams_canonical.json)
        let teamDescriptor = FetchDescriptor<CanonicalTeam>()
        let existingTeams = (try? context.fetch(teamDescriptor)) ?? []
        var teamsCreated: [String: CanonicalTeam] = Dictionary(
            uniqueKeysWithValues: existingTeams.map { ($0.canonicalId, $0) }
        )
        let teamsAlreadyLoaded = !existingTeams.isEmpty

        var seenGameIds = Set<String>()

        for jsonGame in games {
            let sport = jsonGame.sport.uppercased()

            // Legacy team extraction (only if teams not already loaded)
            if !teamsAlreadyLoaded {
                let homeTeamCanonicalId = "team_\(sport.lowercased())_\(jsonGame.home_team_abbrev.lowercased())"
                if teamsCreated[homeTeamCanonicalId] == nil {
                    let stadiumCanonicalId = findStadiumCanonicalId(
                        venue: jsonGame.venue,
                        sport: sport,
                        stadiumsByVenue: stadiumsByVenue
                    )

                    let team = CanonicalTeam(
                        canonicalId: homeTeamCanonicalId,
                        schemaVersion: SchemaVersion.current,
                        lastModified: BundledDataTimestamp.games,
                        source: .bundled,
                        name: extractTeamName(from: jsonGame.home_team),
                        abbreviation: jsonGame.home_team_abbrev,
                        sport: sport,
                        city: extractCity(from: jsonGame.home_team),
                        stadiumCanonicalId: stadiumCanonicalId
                    )
                    context.insert(team)
                    teamsCreated[homeTeamCanonicalId] = team
                }

                let awayTeamCanonicalId = "team_\(sport.lowercased())_\(jsonGame.away_team_abbrev.lowercased())"
                if teamsCreated[awayTeamCanonicalId] == nil {
                    let team = CanonicalTeam(
                        canonicalId: awayTeamCanonicalId,
                        schemaVersion: SchemaVersion.current,
                        lastModified: BundledDataTimestamp.games,
                        source: .bundled,
                        name: extractTeamName(from: jsonGame.away_team),
                        abbreviation: jsonGame.away_team_abbrev,
                        sport: sport,
                        city: extractCity(from: jsonGame.away_team),
                        stadiumCanonicalId: "unknown"
                    )
                    context.insert(team)
                    teamsCreated[awayTeamCanonicalId] = team
                }
            }

            // Deduplicate games
            guard !seenGameIds.contains(jsonGame.id) else { continue }
            seenGameIds.insert(jsonGame.id)

            guard let dateTime = parseDateTime(date: jsonGame.date, time: jsonGame.time ?? "7:00p") else {
                continue
            }

            let homeTeamCanonicalId = "team_\(sport.lowercased())_\(jsonGame.home_team_abbrev.lowercased())"
            let awayTeamCanonicalId = "team_\(sport.lowercased())_\(jsonGame.away_team_abbrev.lowercased())"
            let stadiumCanonicalId = findStadiumCanonicalId(
                venue: jsonGame.venue,
                sport: sport,
                stadiumsByVenue: stadiumsByVenue
            )

            let game = CanonicalGame(
                canonicalId: jsonGame.id,
                schemaVersion: SchemaVersion.current,
                lastModified: BundledDataTimestamp.games,
                source: .bundled,
                homeTeamCanonicalId: homeTeamCanonicalId,
                awayTeamCanonicalId: awayTeamCanonicalId,
                stadiumCanonicalId: stadiumCanonicalId,
                dateTime: dateTime,
                sport: sport,
                season: jsonGame.season,
                isPlayoff: jsonGame.is_playoff,
                broadcastInfo: jsonGame.broadcast
            )
            context.insert(game)
        }
    }

    @MainActor
    private func bootstrapTeamAliases(context: ModelContext) async throws {
        // Team aliases are optional - load if file exists
        guard let url = Bundle.main.url(forResource: "team_aliases", withExtension: "json") else {
            return
        }

        let data: Data
        let aliases: [JSONTeamAlias]

        do {
            data = try Data(contentsOf: url)
            aliases = try JSONDecoder().decode([JSONTeamAlias].self, from: data)
        } catch {
            throw BootstrapError.jsonDecodingFailed("team_aliases.json", error)
        }

        let dateFormatter = ISO8601DateFormatter()

        for jsonAlias in aliases {
            let aliasType: TeamAliasType
            switch jsonAlias.alias_type.lowercased() {
            case "abbreviation": aliasType = .abbreviation
            case "name": aliasType = .name
            case "city": aliasType = .city
            default: aliasType = .name
            }

            let alias = TeamAlias(
                id: jsonAlias.id,
                teamCanonicalId: jsonAlias.team_canonical_id,
                aliasType: aliasType,
                aliasValue: jsonAlias.alias_value,
                validFrom: jsonAlias.valid_from.flatMap { dateFormatter.date(from: $0) },
                validUntil: jsonAlias.valid_until.flatMap { dateFormatter.date(from: $0) },
                schemaVersion: SchemaVersion.current,
                lastModified: BundledDataTimestamp.games
            )
            context.insert(alias)
        }
    }

    // MARK: - Helpers

    @MainActor
    private func createDefaultLeagueStructure(context: ModelContext) {
        // Create minimal league structure for supported sports
        let timestamp = BundledDataTimestamp.leagueStructure

        // MLB
        context.insert(LeagueStructureModel(
            id: "mlb_league",
            sport: "MLB",
            structureType: .league,
            name: "Major League Baseball",
            abbreviation: "MLB",
            displayOrder: 0,
            schemaVersion: SchemaVersion.current,
            lastModified: timestamp
        ))

        // NBA
        context.insert(LeagueStructureModel(
            id: "nba_league",
            sport: "NBA",
            structureType: .league,
            name: "National Basketball Association",
            abbreviation: "NBA",
            displayOrder: 0,
            schemaVersion: SchemaVersion.current,
            lastModified: timestamp
        ))

        // NHL
        context.insert(LeagueStructureModel(
            id: "nhl_league",
            sport: "NHL",
            structureType: .league,
            name: "National Hockey League",
            abbreviation: "NHL",
            displayOrder: 0,
            schemaVersion: SchemaVersion.current,
            lastModified: timestamp
        ))
    }

    // Venue name aliases for stadiums that changed names
    private static let venueAliases: [String: String] = [
        "daikin park": "minute maid park",
        "rate field": "guaranteed rate field",
        "george m. steinbrenner field": "tropicana field",
        "loandepot park": "loandepot park",
    ]

    nonisolated private func findStadiumCanonicalId(
        venue: String,
        sport: String,
        stadiumsByVenue: [String: CanonicalStadium]
    ) -> String {
        var venueLower = venue.lowercased()

        // Check for known aliases
        if let aliasedName = Self.venueAliases[venueLower] {
            venueLower = aliasedName
        }

        // Try exact match
        if let stadium = stadiumsByVenue[venueLower] {
            return stadium.canonicalId
        }

        // Try partial match
        for (name, stadium) in stadiumsByVenue {
            if name.contains(venueLower) || venueLower.contains(name) {
                return stadium.canonicalId
            }
        }

        // Generate deterministic ID for unknown venues
        return "venue_unknown_\(venue.lowercased().replacingOccurrences(of: " ", with: "_"))"
    }

    nonisolated private func parseDateTime(date: String, time: String) -> Date? {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")

        // Parse date
        formatter.dateFormat = "yyyy-MM-dd"
        guard let dateOnly = formatter.date(from: date) else { return nil }

        // Parse time (e.g., "7:30p", "10:00p", "1:05p")
        var hour = 12
        var minute = 0

        let cleanTime = time.lowercased().replacingOccurrences(of: " ", with: "")
        let isPM = cleanTime.contains("p")
        let timeWithoutAMPM = cleanTime.replacingOccurrences(of: "p", with: "").replacingOccurrences(of: "a", with: "")

        let components = timeWithoutAMPM.split(separator: ":")
        if !components.isEmpty, let h = Int(components[0]) {
            hour = h
            if isPM && hour != 12 {
                hour += 12
            } else if !isPM && hour == 12 {
                hour = 0
            }
        }
        if components.count > 1, let m = Int(components[1]) {
            minute = m
        }

        return Calendar.current.date(bySettingHour: hour, minute: minute, second: 0, of: dateOnly)
    }

    nonisolated private func extractTeamName(from fullName: String) -> String {
        // "Boston Celtics" -> "Celtics"
        let parts = fullName.split(separator: " ")
        if parts.count > 1 {
            return parts.dropFirst().joined(separator: " ")
        }
        return fullName
    }

    nonisolated private func extractCity(from fullName: String) -> String {
        // "Boston Celtics" -> "Boston"
        // "New York Knicks" -> "New York"
        let knownCities = [
            "New York", "Los Angeles", "San Francisco", "San Diego", "San Antonio",
            "New Orleans", "Oklahoma City", "Salt Lake City", "Kansas City",
            "St. Louis", "St Louis"
        ]

        for city in knownCities {
            if fullName.hasPrefix(city) {
                return city
            }
        }

        // Default: first word
        return String(fullName.split(separator: " ").first ?? Substring(fullName))
    }

    nonisolated private func stateFromCity(_ city: String) -> String {
        let cityToState: [String: String] = [
            "Atlanta": "GA", "Boston": "MA", "Brooklyn": "NY", "Charlotte": "NC",
            "Chicago": "IL", "Cleveland": "OH", "Dallas": "TX", "Denver": "CO",
            "Detroit": "MI", "Houston": "TX", "Indianapolis": "IN", "Los Angeles": "CA",
            "Memphis": "TN", "Miami": "FL", "Milwaukee": "WI", "Minneapolis": "MN",
            "New Orleans": "LA", "New York": "NY", "Oklahoma City": "OK", "Orlando": "FL",
            "Philadelphia": "PA", "Phoenix": "AZ", "Portland": "OR", "Sacramento": "CA",
            "San Antonio": "TX", "San Francisco": "CA", "Seattle": "WA", "Toronto": "ON",
            "Washington": "DC", "Las Vegas": "NV", "Tampa": "FL", "Pittsburgh": "PA",
            "Baltimore": "MD", "Cincinnati": "OH", "St. Louis": "MO", "Kansas City": "MO",
            "Arlington": "TX", "Anaheim": "CA", "Oakland": "CA", "San Diego": "CA",
            "Tampa Bay": "FL", "St Petersburg": "FL", "Salt Lake City": "UT"
        ]
        return cityToState[city] ?? ""
    }
}
