import Foundation
import SwiftData

@MainActor
final class PersistenceManager {
    private let modelContext: ModelContext

    init(modelContext: ModelContext) {
        self.modelContext = modelContext
    }

    // MARK: - Game State

    func saveGame(variant: GameVariant, difficulty: Difficulty, snapshot: GameSnapshot, elapsedSeconds: Int) {
        // Delete any existing save for this variant
        deleteSavedGame(for: variant)

        let record = GameRecord(variant: variant, difficulty: difficulty,
                                 snapshot: snapshot, elapsedSeconds: elapsedSeconds)
        modelContext.insert(record)
        try? modelContext.save()
    }

    func loadSavedGame(for variant: GameVariant) -> GameRecord? {
        let variantRaw = variant.rawValue
        let descriptor = FetchDescriptor<GameRecord>(
            predicate: #Predicate { $0.variant == variantRaw },
            sortBy: [SortDescriptor(\.lastPlayedDate, order: .reverse)]
        )
        return try? modelContext.fetch(descriptor).first
    }

    func loadMostRecentGame() -> GameRecord? {
        let descriptor = FetchDescriptor<GameRecord>(
            sortBy: [SortDescriptor(\.lastPlayedDate, order: .reverse)]
        )
        return try? modelContext.fetch(descriptor).first
    }

    func deleteSavedGame(for variant: GameVariant) {
        let variantRaw = variant.rawValue
        let descriptor = FetchDescriptor<GameRecord>(
            predicate: #Predicate { $0.variant == variantRaw }
        )
        if let records = try? modelContext.fetch(descriptor) {
            for record in records {
                modelContext.delete(record)
            }
        }
    }

    // MARK: - Statistics

    func recordWin(variant: GameVariant, difficulty: Difficulty, score: Int, time: Int) {
        let record = fetchOrCreateStats(variant: variant, difficulty: difficulty)
        record.recordWin(score: score, time: time)
        try? modelContext.save()
    }

    func recordLoss(variant: GameVariant, difficulty: Difficulty) {
        let record = fetchOrCreateStats(variant: variant, difficulty: difficulty)
        record.recordLoss()
        try? modelContext.save()
    }

    func fetchStats(variant: GameVariant, difficulty: Difficulty) -> StatsRecord? {
        let variantRaw = variant.rawValue
        let difficultyRaw = difficulty.rawValue
        let descriptor = FetchDescriptor<StatsRecord>(
            predicate: #Predicate { $0.variant == variantRaw && $0.difficulty == difficultyRaw }
        )
        return try? modelContext.fetch(descriptor).first
    }

    private func fetchOrCreateStats(variant: GameVariant, difficulty: Difficulty) -> StatsRecord {
        if let existing = fetchStats(variant: variant, difficulty: difficulty) {
            return existing
        }
        let record = StatsRecord(variant: variant, difficulty: difficulty)
        modelContext.insert(record)
        return record
    }

    // MARK: - Preferences

    func loadPreferences() -> PrefsRecord {
        let descriptor = FetchDescriptor<PrefsRecord>()
        if let existing = try? modelContext.fetch(descriptor).first {
            return existing
        }
        let record = PrefsRecord()
        modelContext.insert(record)
        try? modelContext.save()
        return record
    }

    func savePreferences(themeId: String, cardFaceStyle: CardFaceStyle,
                          cardBackDesign: CardBackDesign, soundEnabled: Bool,
                          lastVariant: GameVariant, lastDifficulty: Difficulty) {
        let prefs = loadPreferences()
        prefs.themeId = themeId
        prefs.cardFaceStyle = cardFaceStyle.rawValue
        prefs.cardBackDesign = cardBackDesign.rawValue
        prefs.soundEnabled = soundEnabled
        prefs.lastVariant = lastVariant.rawValue
        prefs.lastDifficulty = lastDifficulty.rawValue
        try? modelContext.save()
    }
}
