import SwiftUI
import SharedModels
import SwiftData

/// Due-card review for the noun flashcard SRS — the non-verb analog of
/// `VocabReviewView`. Pulls every `LexemeReviewCard` with
/// `partOfSpeech == "noun"` whose `dueDate` is in the past, shows the
/// Spanish word with its article on the front, reveals the English, then
/// rates via the SRS so the schedule moves forward.
struct NounReviewView: View {
    @Environment(\.cloudModelContextProvider) private var cloudModelContextProvider
    @Environment(\.modelContext) private var localContext
    @Environment(\.dismiss) private var dismiss

    @State private var dueCards: [LexemeReviewCard] = []
    @State private var lexemesByID: [String: Lexeme] = [:]
    @State private var currentIndex = 0
    @State private var isRevealed = false
    @State private var sessionCorrect = 0
    @State private var sessionTotal = 0
    @State private var isFinished = false

    private var cloudContext: ModelContext { cloudModelContextProvider() }

    var body: some View {
        VStack(spacing: 20) {
            if isFinished || dueCards.isEmpty {
                finishedView
            } else if let card = dueCards[safe: currentIndex] {
                cardView(card)
            }
        }
        .padding()
        .adaptiveContainer(maxWidth: 600)
        .navigationTitle("Noun Review")
        .navigationBarTitleDisplayMode(.inline)
        .onAppear(perform: loadDueCards)
    }

    @ViewBuilder
    private func cardView(_ card: LexemeReviewCard) -> some View {
        let lexeme = lexemesByID[card.lexemeId]
        VStack(spacing: 24) {
            Text("\(currentIndex + 1) of \(dueCards.count)")
                .font(.caption.weight(.medium))
                .foregroundStyle(.secondary)

            ProgressView(value: Double(currentIndex), total: Double(dueCards.count))
                .tint(.teal)

            Spacer()

            Text(spanishFront(lexeme))
                .font(.largeTitle.bold())
                .multilineTextAlignment(.center)

            if isRevealed {
                Text(lexeme?.english ?? "")
                    .font(.title2)
                    .foregroundStyle(.secondary)
                    .transition(.opacity.combined(with: .move(edge: .bottom)))

                Spacer()

                HStack(spacing: 12) {
                    ratingButton("Again", color: .red, quality: .again)
                    ratingButton("Hard", color: .orange, quality: .hard)
                    ratingButton("Good", color: .green, quality: .good)
                    ratingButton("Easy", color: .blue, quality: .easy)
                }
            } else {
                Spacer()

                Button {
                    withAnimation { isRevealed = true }
                } label: {
                    Text("Show Answer")
                        .font(.headline)
                        .frame(maxWidth: .infinity)
                        .padding(.vertical, 12)
                }
                .buttonStyle(.borderedProminent)
                .tint(.teal)
            }
        }
    }

    private var finishedView: some View {
        VStack(spacing: 20) {
            Spacer()
            Image(systemName: dueCards.isEmpty ? "checkmark.seal.fill" : "star.fill")
                .font(.system(size: 60))
                .foregroundStyle(dueCards.isEmpty ? .green : .yellow)

            if dueCards.isEmpty {
                Text("All caught up!").font(.title2.bold())
                Text("No noun cards are due for review.")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            } else {
                Text("\(sessionCorrect) / \(sessionTotal)")
                    .font(.system(size: 48, weight: .bold).monospacedDigit())
                Text("Review complete!").font(.title3).foregroundStyle(.secondary)
            }
            Spacer()
        }
    }

    private func ratingButton(_ label: String, color: Color, quality: ReviewQuality) -> some View {
        Button {
            rate(quality: quality)
        } label: {
            Text(label)
                .font(.subheadline.weight(.semibold))
                .frame(maxWidth: .infinity)
                .padding(.vertical, 10)
        }
        .buttonStyle(.bordered)
        .tint(color)
    }

    private func rate(quality: ReviewQuality) {
        guard let card = dueCards[safe: currentIndex] else { return }

        ReviewStore.recordActivity(context: cloudContext)
        let result = SRSEngine.review(
            quality: quality,
            currentEase: card.easeFactor,
            currentInterval: card.interval,
            currentReps: card.repetitions
        )
        card.easeFactor = result.easeFactor
        card.interval = result.interval
        card.repetitions = result.repetitions
        card.dueDate = SRSEngine.nextDueDate(interval: result.interval)
        card.lastReviewDate = Date()
        try? cloudContext.save()

        sessionTotal += 1
        if quality != .again { sessionCorrect += 1 }

        isRevealed = false
        if currentIndex + 1 < dueCards.count {
            currentIndex += 1
        } else {
            withAnimation { isFinished = true }
        }
    }

    private func loadDueCards() {
        let now = Date()
        let pos = "noun"
        let descriptor = FetchDescriptor<LexemeReviewCard>(
            predicate: #Predicate<LexemeReviewCard> {
                $0.partOfSpeech == pos && $0.dueDate <= now
            },
            sortBy: [SortDescriptor(\LexemeReviewCard.dueDate)]
        )
        dueCards = (try? cloudContext.fetch(descriptor)) ?? []

        let ids = Set(dueCards.map(\.lexemeId))
        let lexDesc = FetchDescriptor<Lexeme>(
            predicate: #Predicate<Lexeme> { ids.contains($0.id) }
        )
        let all = (try? localContext.fetch(lexDesc)) ?? []
        lexemesByID = Dictionary(all.map { ($0.id, $0) }, uniquingKeysWith: { existing, _ in existing })
    }

    static func dueCount(context: ModelContext) -> Int {
        let now = Date()
        let pos = "noun"
        let descriptor = FetchDescriptor<LexemeReviewCard>(
            predicate: #Predicate<LexemeReviewCard> {
                $0.partOfSpeech == pos && $0.dueDate <= now
            }
        )
        return (try? context.fetchCount(descriptor)) ?? 0
    }

    private func spanishFront(_ lexeme: Lexeme?) -> String {
        guard let lexeme else { return "" }
        guard let g = lexeme.gender, !g.isEmpty else { return lexeme.baseForm }
        let article: String
        switch g {
        case "f": article = "la"
        case "m/f": article = "el/la"
        default: article = "el"
        }
        return "\(article) \(lexeme.baseForm)"
    }
}

private extension Collection {
    subscript(safe index: Index) -> Element? {
        indices.contains(index) ? self[index] : nil
    }
}
