import WidgetKit
import SwiftUI
import SwiftData
import SharedModels

struct CombinedEntry: TimelineEntry {
    let date: Date
    let word: WordOfDay?
    let data: WidgetData
}

struct CombinedProvider: TimelineProvider {
    private static let previewWord = WordOfDay(spanish: "hablar", english: "to speak", subtitle: "Level: Basic")

    func placeholder(in context: Context) -> CombinedEntry {
        CombinedEntry(date: Date(), word: Self.previewWord, data: .placeholder)
    }

    func getSnapshot(in context: Context, completion: @escaping (CombinedEntry) -> Void) {
        if context.isPreview {
            completion(CombinedEntry(date: Date(), word: Self.previewWord, data: .placeholder))
            return
        }
        let word = fetchWordOfDay(for: Date())
        let data = WidgetDataReader.read()
        completion(CombinedEntry(date: Date(), word: word, data: data))
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<CombinedEntry>) -> Void) {
        let word = fetchWordOfDay(for: Date())
        let data = WidgetDataReader.read()
        let entry = CombinedEntry(date: Date(), word: word, data: data)

        // Expire at midnight for new word
        let tomorrow = Calendar.current.startOfDay(
            for: Calendar.current.date(byAdding: .day, value: 1, to: Date())!
        )
        completion(Timeline(entries: [entry], policy: .after(tomorrow)))
    }

    private func fetchWordOfDay(for date: Date) -> WordOfDay? {
        guard let localURL = SharedStore.localStoreURL() else { return nil }

        // Open the store with the SAME schema as the main app. A subset schema
        // would make SwiftData destructively migrate the store on open and drop
        // every unlisted table (this is how widget refreshes kept wiping the
        // bundled Book rows, and TextbookChapter before them).
        let schema = Schema(SharedStore.localSchemaModels)
        let config = ModelConfiguration(
            "local",
            schema: schema,
            url: localURL,
            cloudKitDatabase: .none
        )
        guard let container = try? ModelContainer(
            for: schema,
            configurations: config
        ) else { return nil }

        let context = ModelContext(container)
        let defaults = UserDefaults(suiteName: "group.com.conjuga.app")
        let wordOffset = defaults?.integer(forKey: "wordOffset") ?? 0
        let selectedLevel = defaults?.string(forKey: "selectedVerbLevel") ?? "basic"

        guard let verb = VerbStore.fetchVerbOfDay(
            for: date,
            dayOffset: wordOffset,
            selectedLevel: selectedLevel,
            context: context
        ) else { return nil }

        return WordOfDay(
            spanish: verb.infinitive,
            english: verb.english,
            subtitle: "Level: \(selectedLevel.capitalized)"
        )
    }
}

struct CombinedWidget: Widget {
    let kind = "CombinedWidget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: CombinedProvider()) { entry in
            CombinedWidgetView(entry: entry)
                .containerBackground(.fill.tertiary, for: .widget)
        }
        .configurationDisplayName("Conjuga Overview")
        .description("Word of the day with daily stats and progress.")
        .supportedFamilies([.systemLarge])
    }
}

struct CombinedWidgetView: View {
    let entry: CombinedEntry

    var body: some View {
        VStack(spacing: 16) {
            // Word of the Day section
            if let word = entry.word {
                VStack(spacing: 6) {
                    Text("WORD OF THE DAY")
                        .font(.caption2.weight(.bold))
                        .foregroundStyle(.orange)
                        .tracking(1.5)

                    Text(word.spanish)
                        .font(.largeTitle.bold())
                        .minimumScaleFactor(0.5)
                        .lineLimit(1)

                    Text(word.english)
                        .font(.title3)
                        .foregroundStyle(.secondary)

                    HStack(spacing: 12) {
                        Text(word.subtitle)
                            .font(.caption2)
                            .foregroundStyle(.tertiary)

                        Button(intent: NewWordIntent()) {
                            Label("New Word", systemImage: "arrow.triangle.2.circlepath")
                                .font(.caption2)
                        }
                        .tint(.orange)
                    }
                }
                .frame(maxWidth: .infinity)
            }

            Divider()

            // Stats grid
            HStack(spacing: 0) {
                // Daily progress
                VStack(spacing: 6) {
                    ZStack {
                        Circle()
                            .stroke(.quaternary, lineWidth: 5)
                        Circle()
                            .trim(from: 0, to: entry.data.progressPercent)
                            .stroke(.orange, style: StrokeStyle(lineWidth: 5, lineCap: .round))
                            .rotationEffect(.degrees(-90))
                        VStack(spacing: 0) {
                            Text("\(entry.data.todayCount)")
                                .font(.title3.bold().monospacedDigit())
                            Text("/\(entry.data.dailyGoal)")
                                .font(.caption2)
                                .foregroundStyle(.secondary)
                        }
                    }
                    .frame(width: 60, height: 60)

                    Text("Today")
                        .font(.caption2)
                        .foregroundStyle(.secondary)
                }
                .frame(maxWidth: .infinity)

                // Streak
                VStack(spacing: 6) {
                    Image(systemName: "flame.fill")
                        .font(.title)
                        .foregroundStyle(.orange)

                    Text("\(entry.data.currentStreak)")
                        .font(.title3.bold().monospacedDigit())

                    Text("Streak")
                        .font(.caption2)
                        .foregroundStyle(.secondary)
                }
                .frame(maxWidth: .infinity)

                // Due cards
                VStack(spacing: 6) {
                    Image(systemName: "clock.badge.exclamationmark")
                        .font(.title)
                        .foregroundStyle(entry.data.dueCardCount > 0 ? .blue : .secondary)

                    Text("\(entry.data.dueCardCount)")
                        .font(.title3.bold().monospacedDigit())

                    Text("Due")
                        .font(.caption2)
                        .foregroundStyle(.secondary)
                }
                .frame(maxWidth: .infinity)

                // Test score
                VStack(spacing: 6) {
                    Image(systemName: entry.data.latestTestScore ?? 0 >= 90 ? "star.fill" : "pencil.and.list.clipboard")
                        .font(.title)
                        .foregroundStyle(scoreColor)

                    if let score = entry.data.latestTestScore {
                        Text("\(score)%")
                            .font(.title3.bold().monospacedDigit())
                    } else {
                        Text("—")
                            .font(.title3.bold())
                    }

                    Text("Test")
                        .font(.caption2)
                        .foregroundStyle(.secondary)
                }
                .frame(maxWidth: .infinity)
            }
        }
        .padding(.vertical, 8)
    }

    private var scoreColor: Color {
        guard let score = entry.data.latestTestScore else { return .secondary }
        if score >= 90 { return .yellow }
        if score >= 70 { return .green }
        return .orange
    }
}

#Preview(as: .systemLarge) {
    CombinedWidget()
} timeline: {
    CombinedEntry(
        date: Date(),
        word: WordOfDay(spanish: "hablar", english: "to speak", subtitle: "Level: Basic"),
        data: .placeholder
    )
}
