import SwiftUI
import SharedModels
import SwiftData

struct ListeningView: View {
    @Environment(\.modelContext) private var localContext
    @Environment(\.cloudModelContextProvider) private var cloudModelContextProvider
    private var cloudModelContext: ModelContext { cloudModelContextProvider() }
    @State private var pronunciation = PronunciationService()
    @State private var speechService = SpeechService()

    @State private var sentences: [(spanish: String, english: String)] = []
    @State private var currentIndex = 0
    @State private var userInput = ""
    @State private var isRevealed = false
    @State private var score: Double?
    @State private var wordMatches: [PronunciationService.WordMatch] = []
    @State private var mode: ListeningMode = .listenType
    @State private var correctCount = 0
    @State private var isFinished = false

    enum ListeningMode: String, CaseIterable {
        case listenType = "Listen & Type"
        case speakCheck = "Pronunciation"
    }

    var body: some View {
        VStack(spacing: 20) {
            if isFinished {
                finishedView
            } else if sentences.isEmpty {
                ContentUnavailableView("No sentences available", systemImage: "waveform", description: Text("Complete some course decks first."))
            } else {
                exerciseView
            }
        }
        .padding()
        .adaptiveContainer(maxWidth: 600)
        .navigationTitle("Listening Practice")
        .navigationBarTitleDisplayMode(.inline)
        .onAppear {
            print("[ListeningView] onAppear — loading sentences")
            loadSentences()
            print("[ListeningView] loaded \(sentences.count) sentences, requesting auth")
            Task {
                pronunciation.requestAuthorization()
            }
        }
    }

    // MARK: - Exercise

    @ViewBuilder
    private var exerciseView: some View {
        VStack(spacing: 20) {
            // Mode picker
            Picker("Mode", selection: $mode) {
                ForEach(ListeningMode.allCases, id: \.self) { m in
                    Text(m.rawValue).tag(m)
                }
            }
            .pickerStyle(.segmented)

            Text("\(currentIndex + 1) / \(sentences.count)")
                .font(.caption.weight(.medium))
                .foregroundStyle(.secondary)

            if mode == .listenType {
                listenAndTypeView
            } else {
                pronunciationCheckView
            }
        }
    }

    // MARK: - Listen & Type

    @ViewBuilder
    private var listenAndTypeView: some View {
        let sentence = sentences[currentIndex]

        VStack(spacing: 16) {
            // Play button
            Button {
                speechService.speak(sentence.spanish)
            } label: {
                Label("Play", systemImage: "speaker.wave.2.fill")
                    .font(.headline)
                    .padding()
                    .frame(maxWidth: .infinity)
            }
            .buttonStyle(.bordered)
            .tint(.blue)

            // User types what they heard
            TextField("Type what you hear...", text: $userInput)
                .textFieldStyle(.roundedBorder)
                .autocorrectionDisabled()
                .textInputAutocapitalization(.never)

            if isRevealed {
                // Show correct answer
                VStack(alignment: .leading, spacing: 8) {
                    Text("Correct:")
                        .font(.caption.weight(.semibold))
                        .foregroundStyle(.secondary)
                    Text(sentence.spanish)
                        .font(.body.weight(.medium))
                    Text(sentence.english)
                        .font(.callout)
                        .foregroundStyle(.secondary)

                    let result = PronunciationService.scoreMatch(expected: sentence.spanish, spoken: userInput)
                    Text("Score: \(Int(result.score * 100))%")
                        .font(.headline)
                        .foregroundStyle(result.score >= 0.8 ? .green : result.score >= 0.5 ? .orange : .red)
                }
                .padding()
                .frame(maxWidth: .infinity, alignment: .leading)
                .background(.fill.quinary, in: RoundedRectangle(cornerRadius: 12))

                nextButton
            } else {
                Button {
                    let result = PronunciationService.scoreMatch(expected: sentence.spanish, spoken: userInput)
                    if result.score >= 0.7 { correctCount += 1 }
                    ReviewStore.recordActivity(context: cloudModelContext)
                    withAnimation { isRevealed = true }
                } label: {
                    Text("Check")
                        .font(.headline)
                        .frame(maxWidth: .infinity)
                        .padding(.vertical, 12)
                }
                .buttonStyle(.borderedProminent)
                .tint(.blue)
                .disabled(userInput.isEmpty)
            }
        }
    }

    // MARK: - Pronunciation Check

    @ViewBuilder
    private var pronunciationCheckView: some View {
        let sentence = sentences[currentIndex]

        VStack(spacing: 16) {
            // Show the sentence to read
            Text(sentence.spanish)
                .font(.title3.weight(.medium))
                .multilineTextAlignment(.center)
                .padding()
                .frame(maxWidth: .infinity)
                .background(.fill.quinary, in: RoundedRectangle(cornerRadius: 12))

            Text(sentence.english)
                .font(.callout)
                .foregroundStyle(.secondary)

            // Mic button
            Button {
                if pronunciation.isRecording {
                    pronunciation.stopRecording()
                    // Score after stopping
                    let result = PronunciationService.scoreMatch(expected: sentence.spanish, spoken: pronunciation.transcript)
                    score = result.score
                    wordMatches = result.matches
                    if result.score >= 0.7 { correctCount += 1 }
                    ReviewStore.recordActivity(context: cloudModelContext)
                    withAnimation { isRevealed = true }
                } else {
                    pronunciation.startRecording()
                }
            } label: {
                Label(pronunciation.isRecording ? "Stop" : "Start Speaking", systemImage: pronunciation.isRecording ? "stop.circle.fill" : "mic.circle.fill")
                    .font(.headline)
                    .padding()
                    .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
            .tint(pronunciation.isRecording ? .red : .green)
            .disabled(!pronunciation.isAuthorized)

            if !pronunciation.isAuthorized {
                Text("Microphone access required. Enable in Settings.")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            if pronunciation.isRecording {
                Text(pronunciation.transcript.isEmpty ? "Listening..." : pronunciation.transcript)
                    .font(.body)
                    .foregroundStyle(.secondary)
                    .italic()
            }

            if isRevealed, let score {
                VStack(spacing: 8) {
                    Text("\(Int(score * 100))% match")
                        .font(.title2.bold())
                        .foregroundStyle(score >= 0.8 ? .green : score >= 0.5 ? .orange : .red)

                    // Word-by-word feedback
                    FlowLayout(spacing: 4) {
                        ForEach(wordMatches) { match in
                            Text(match.word)
                                .font(.body)
                                .foregroundStyle(match.matched ? .green : .red)
                                .padding(.horizontal, 6)
                                .padding(.vertical, 2)
                                .background(match.matched ? .green.opacity(0.1) : .red.opacity(0.1), in: Capsule())
                        }
                    }
                }
                .padding()
                .background(.fill.quinary, in: RoundedRectangle(cornerRadius: 12))

                nextButton
            }
        }
    }

    // MARK: - Shared

    private var nextButton: some View {
        Button {
            if currentIndex + 1 < sentences.count {
                currentIndex += 1
                userInput = ""
                isRevealed = false
                score = nil
                wordMatches = []
            } else {
                withAnimation { isFinished = true }
            }
        } label: {
            Text(currentIndex + 1 < sentences.count ? "Next" : "See Results")
                .font(.headline)
                .frame(maxWidth: .infinity)
                .padding(.vertical, 12)
        }
        .buttonStyle(.borderedProminent)
        .tint(.blue)
    }

    private var finishedView: some View {
        VStack(spacing: 20) {
            Spacer()
            Image(systemName: "ear.fill")
                .font(.system(size: 60))
                .foregroundStyle(.blue)
            Text("\(correctCount) / \(sentences.count)")
                .font(.system(size: 48, weight: .bold).monospacedDigit())
            Text("Listening complete!")
                .font(.title3)
                .foregroundStyle(.secondary)
            Spacer()
        }
    }

    private func loadSentences() {
        print("[ListeningView] fetching VocabCards from localContext...")
        print("[ListeningView] context: \(localContext)")
        let descriptor = FetchDescriptor<VocabCard>()
        let cards: [VocabCard]
        do {
            let count = try localContext.fetchCount(descriptor)
            print("[ListeningView] fetchCount = \(count)")
            cards = try localContext.fetch(descriptor)
            print("[ListeningView] fetched \(cards.count) VocabCards")
        } catch {
            print("[ListeningView] ERROR fetching VocabCards: \(error)")
            return
        }

        var results: [(String, String)] = []
        for card in cards.shuffled() {
            for i in card.examplesES.indices {
                let es = card.examplesES[i]
                let en = i < card.examplesEN.count ? card.examplesEN[i] : ""
                if es.split(separator: " ").count >= 4 {
                    results.append((es, en))
                }
                if results.count >= 10 { break }
            }
            if results.count >= 10 { break }
        }
        sentences = results
        print("[ListeningView] selected \(sentences.count) sentences")
    }
}

// Reuse FlowLayout from StoryReaderView — import not needed since it's in the same module
// but we need a local copy since it's private there
private struct FlowLayout: Layout {
    var spacing: CGFloat = 0
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        let rows = computeRows(proposal: proposal, subviews: subviews)
        var height: CGFloat = 0
        for row in rows { height += row.map { $0.height }.max() ?? 0 }
        height += CGFloat(max(0, rows.count - 1)) * spacing
        return CGSize(width: proposal.width ?? 0, height: height)
    }
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        let rows = computeRows(proposal: proposal, subviews: subviews)
        var y = bounds.minY; var idx = 0
        for row in rows {
            var x = bounds.minX; let rh = row.map { $0.height }.max() ?? 0
            for size in row { subviews[idx].place(at: CGPoint(x: x, y: y), proposal: ProposedViewSize(size)); x += size.width; idx += 1 }
            y += rh + spacing
        }
    }
    private func computeRows(proposal: ProposedViewSize, subviews: Subviews) -> [[CGSize]] {
        let mw = proposal.width ?? .infinity; var rows: [[CGSize]] = [[]]; var cw: CGFloat = 0
        for sv in subviews {
            let s = sv.sizeThatFits(.unspecified)
            if cw + s.width > mw && !rows[rows.count - 1].isEmpty { rows.append([]); cw = 0 }
            rows[rows.count - 1].append(s); cw += s.width
        }
        return rows
    }
}
