import Foundation
import SharedModels
import SwiftData
import WidgetKit

/// Writes widget data to shared App Group container.
@MainActor
struct WidgetDataService {
    static let suiteName = "group.com.conjuga.app"
    static let dataKey = "widgetData"

    static func update(localContainer: ModelContainer, cloudContainer: ModelContainer) {
        let localContext = ModelContext(localContainer)
        let cloudContext = ModelContext(cloudContainer)
        update(localContext: localContext, cloudContext: cloudContext)
    }

    static func update(localContext: ModelContext, cloudContext: ModelContext) {
        guard let shared = UserDefaults(suiteName: suiteName) else { return }

        let progress = ReviewStore.fetchOrCreateUserProgress(context: cloudContext)

        // Mirror the user's selected verb level into shared UserDefaults so the
        // widget (a separate process with no access to the cloud/CloudKit store)
        // can read it when picking the word of the day.
        shared.set(progress.selectedLevel, forKey: "selectedVerbLevel")

        let now = Date()
        let dueDescriptor = FetchDescriptor<ReviewCard>(
            predicate: #Predicate<ReviewCard> { $0.dueDate <= now }
        )
        let dueCount = (try? cloudContext.fetchCount(dueDescriptor)) ?? 0

        // Cache a verb-based word-of-the-day for the CombinedWidget's stats
        // fallback path. Widgets that display the word directly call
        // VerbStore.fetchVerbOfDay themselves.
        var wordOfDay: WordOfDay?
        let wordOffset = shared.integer(forKey: "wordOffset")
        if let verb = VerbStore.fetchVerbOfDay(
            for: now,
            dayOffset: wordOffset,
            selectedLevel: progress.selectedLevel,
            context: localContext
        ) {
            wordOfDay = WordOfDay(
                spanish: verb.infinitive,
                english: verb.english,
                subtitle: "Level: \(progress.selectedLevel.capitalized)"
            )
        }

        let testDescriptor = FetchDescriptor<TestResult>(
            sortBy: [SortDescriptor(\TestResult.dateTaken, order: .reverse)]
        )
        let latestTest = (try? cloudContext.fetch(testDescriptor))?.first
        let currentWeek = latestTest?.weekNumber ?? 1

        let previousData = shared.data(forKey: dataKey)
            .flatMap { try? JSONDecoder().decode(WidgetData.self, from: $0) }

        var data = WidgetData(
            todayCount: progress.todayCount,
            dailyGoal: progress.dailyGoal,
            currentStreak: progress.currentStreak,
            dueCardCount: dueCount,
            wordOfTheDay: wordOfDay,
            latestTestScore: latestTest?.scorePercent,
            latestTestWeek: latestTest?.weekNumber,
            currentWeek: currentWeek,
            lastUpdated: previousData?.lastUpdated ?? now
        )

        if previousData == data {
            return
        }

        data.lastUpdated = now

        if let encoded = try? JSONEncoder().encode(data) {
            shared.set(encoded, forKey: dataKey)
            WidgetCenter.shared.reloadAllTimelines()
        }
    }

    /// Read widget data (used by widget extension).
    static func read() -> WidgetData {
        guard let shared = UserDefaults(suiteName: suiteName),
              let data = shared.data(forKey: dataKey),
              let decoded = try? JSONDecoder().decode(WidgetData.self, from: data) else {
            return WidgetData.placeholder
        }
        return decoded
    }
}
