import WidgetKit
import SwiftUI
import SwiftData
import SharedModels

struct WordOfDayEntry: TimelineEntry {
    let date: Date
    let word: WordOfDay?
}

struct WordOfDayProvider: TimelineProvider {
    func placeholder(in context: Context) -> WordOfDayEntry {
        WordOfDayEntry(date: Date(), word: WordOfDay(spanish: "hablar", english: "to speak", subtitle: "Level: Basic"))
    }

    func getSnapshot(in context: Context, completion: @escaping (WordOfDayEntry) -> Void) {
        if context.isPreview {
            completion(WordOfDayEntry(date: Date(), word: WordOfDay(spanish: "hablar", english: "to speak", subtitle: "Level: Basic")))
            return
        }
        completion(WordOfDayEntry(date: Date(), word: fetchWordOfDay(for: Date())))
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<WordOfDayEntry>) -> Void) {
        let entry = WordOfDayEntry(date: Date(), word: fetchWordOfDay(for: Date()))
        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 WordOfDayWidget: Widget {
    let kind = "WordOfDayWidget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: WordOfDayProvider()) { entry in
            WordOfDayWidgetView(entry: entry)
                .containerBackground(.fill.tertiary, for: .widget)
        }
        .configurationDisplayName("Word of the Day")
        .description("Learn a new Spanish word every day.")
        .supportedFamilies([.systemSmall, .systemMedium])
    }
}

struct WordOfDayWidgetView: View {
    @Environment(\.widgetFamily) var family
    let entry: WordOfDayEntry

    var body: some View {
        if let word = entry.word {
            switch family {
            case .systemSmall:
                smallView(word: word)
            case .systemMedium:
                mediumView(word: word)
            default:
                smallView(word: word)
            }
        } else {
            VStack {
                Image(systemName: "textformat.abc")
                    .font(.title)
                    .foregroundStyle(.secondary)
                Text("Open Conjuga to start")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
        }
    }

    private func smallView(word: WordOfDay) -> some View {
        VStack(spacing: 8) {
            Text("Word of the Day")
                .font(.caption2)
                .foregroundStyle(.secondary)
                .textCase(.uppercase)

            Text(word.spanish)
                .font(.title2.bold())
                .minimumScaleFactor(0.6)
                .lineLimit(1)

            Text(word.english)
                .font(.subheadline)
                .foregroundStyle(.secondary)
                .minimumScaleFactor(0.6)
                .lineLimit(2)
                .multilineTextAlignment(.center)

            Text(word.subtitle)
                .font(.caption2)
                .foregroundStyle(.orange)
        }
    }

    private func mediumView(word: WordOfDay) -> some View {
        HStack(spacing: 16) {
            VStack(spacing: 4) {
                Text("WORD OF THE DAY")
                    .font(.caption2.weight(.semibold))
                    .foregroundStyle(.orange)

                Text(word.spanish)
                    .font(.largeTitle.bold())
                    .minimumScaleFactor(0.5)
                    .lineLimit(1)
            }
            .frame(maxWidth: .infinity)

            Divider()

            VStack(alignment: .leading, spacing: 8) {
                VStack(alignment: .leading, spacing: 2) {
                    Text("English")
                        .font(.caption2)
                        .foregroundStyle(.secondary)
                    Text(word.english)
                        .font(.headline)
                        .lineLimit(2)
                }

                HStack {
                    Image(systemName: "tag")
                        .font(.caption2)
                    Text(word.subtitle)
                        .font(.caption2)
                }
                .foregroundStyle(.secondary)
            }
            .frame(maxWidth: .infinity, alignment: .leading)
        }
        .padding(.horizontal, 4)
    }
}

#Preview(as: .systemSmall) {
    WordOfDayWidget()
} timeline: {
    WordOfDayEntry(date: Date(), word: WordOfDay(spanish: "hablar", english: "to speak", subtitle: "Level: Basic"))
}

#Preview(as: .systemMedium) {
    WordOfDayWidget()
} timeline: {
    WordOfDayEntry(date: Date(), word: WordOfDay(spanish: "hablar", english: "to speak", subtitle: "Level: Basic"))
}
