import SwiftUI
import SwiftData
import Charts

struct DashboardView: View {
    @Environment(\.cloudModelContextProvider) private var cloudModelContextProvider
    @Environment(StudyTimerService.self) private var studyTimer
    @State private var userProgress: UserProgress?
    @State private var dailyLogs: [DailyLog] = []
    @State private var testResults: [TestResult] = []
    @State private var reviewCards: [ReviewCard] = []
    @State private var showingSettings = false

    private var cloudModelContext: ModelContext { cloudModelContextProvider() }

    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: 24) {
                    // Summary stats
                    statsGrid

                    // Study time + Activity — side by side on iPad, stacked on iPhone
                    ViewThatFits(in: .horizontal) {
                        HStack(alignment: .top, spacing: 12) {
                            studyTimeCard
                            streakCalendar
                        }
                        VStack(spacing: 12) {
                            studyTimeCard
                            streakCalendar
                        }
                    }

                    // Accuracy chart
                    accuracyChart

                    // Test scores
                    if !testResults.isEmpty {
                        testScoresSection
                    }
                }
                .padding()
                .adaptiveContainer(maxWidth: 800)
            }
            .navigationTitle("Dashboard")
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button {
                        showingSettings = true
                    } label: {
                        Image(systemName: "gearshape")
                    }
                    .accessibilityLabel("Settings")
                }
            }
            .sheet(isPresented: $showingSettings) {
                SettingsView()
            }
            .onAppear(perform: loadData)
        }
    }

    // MARK: - Stats Grid

    private var statsGrid: some View {
        LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 12) {
            StatCard(title: "Total Reviews", value: "\(userProgress?.totalReviewed ?? 0)", icon: "checkmark.circle", color: .blue)

            StatCard(title: "Current Streak", value: "\(userProgress?.currentStreak ?? 0)d", icon: "flame.fill", color: .orange)

            StatCard(title: "Longest Streak", value: "\(userProgress?.longestStreak ?? 0)d", icon: "trophy.fill", color: .yellow)

            let mastered = reviewCards.filter { $0.interval >= 21 }.count
            StatCard(title: "Verbs Mastered", value: "\(mastered)", icon: "star.fill", color: .green)

            let avgAccuracy = averageAccuracy
            StatCard(title: "Avg Accuracy", value: "\(avgAccuracy)%", icon: "target", color: .purple)

            StatCard(title: "Tests Taken", value: "\(testResults.count)", icon: "pencil.and.list.clipboard", color: .indigo)
        }
    }

    // MARK: - Study Time Card

    private var studyTimeCard: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Study Time")
                .font(.headline)

            let todaySeconds = todayStudySeconds + studyTimer.currentSessionSeconds
            HStack(spacing: 0) {
                VStack(spacing: 4) {
                    Text(formatStudyTime(todaySeconds))
                        .font(.title3.bold().monospacedDigit())
                    Text("Today")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
                .frame(maxWidth: .infinity)

                VStack(spacing: 4) {
                    Text(formatStudyTime(totalStudySeconds))
                        .font(.title3.bold().monospacedDigit())
                    Text("Total")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
                .frame(maxWidth: .infinity)
            }

            if weeklyStudyData.allSatisfy({ $0.minutes == 0 }) {
                Text("Start studying to see your time")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .frame(maxWidth: .infinity, minHeight: 80)
            } else {
                Chart(weeklyStudyData) { day in
                    BarMark(
                        x: .value("Day", day.label),
                        y: .value("Minutes", day.minutes)
                    )
                    .foregroundStyle(.mint.gradient)
                    .cornerRadius(4)
                }
                .chartYAxis(.hidden)
                .frame(height: 80)
            }
        }
        .padding()
        .frame(maxWidth: .infinity)
        .background(.fill.quinary, in: RoundedRectangle(cornerRadius: 16))
    }

    // MARK: - Streak Calendar

    private var streakCalendar: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Activity")
                .font(.headline)

            StreakCalendarView(dailyLogs: dailyLogs)
        }
        .padding()
        .frame(maxWidth: .infinity)
        .background(.fill.quinary, in: RoundedRectangle(cornerRadius: 16))
    }

    // MARK: - Accuracy Chart

    private var accuracyChart: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Accuracy (Last 30 Days)")
                .font(.headline)

            if recentLogs.isEmpty {
                Text("Start practicing to see your accuracy trend")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
                    .frame(height: 150)
            } else {
                Chart(recentLogs, id: \.dateString) { log in
                    LineMark(
                        x: .value("Date", DailyLog.date(from: log.dateString) ?? Date()),
                        y: .value("Accuracy", log.accuracy * 100)
                    )
                    .foregroundStyle(.blue)
                    .interpolationMethod(.catmullRom)

                    AreaMark(
                        x: .value("Date", DailyLog.date(from: log.dateString) ?? Date()),
                        y: .value("Accuracy", log.accuracy * 100)
                    )
                    .foregroundStyle(.blue.opacity(0.1))
                    .interpolationMethod(.catmullRom)
                }
                .chartYScale(domain: 0...100)
                .chartYAxis {
                    AxisMarks(values: [0, 25, 50, 75, 100]) { value in
                        AxisValueLabel {
                            Text("\(value.as(Int.self) ?? 0)%")
                                .font(.caption2)
                        }
                        AxisGridLine()
                    }
                }
                .frame(height: 180)
            }
        }
        .padding()
        .background(.fill.quinary, in: RoundedRectangle(cornerRadius: 16))
    }

    // MARK: - Test Scores

    private var testScoresSection: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                Text("Recent Tests")
                    .font(.headline)
                Spacer()
                if let best = testResults.map(\.scorePercent).max() {
                    Text("Best: \(best)%")
                        .font(.caption.weight(.semibold))
                        .foregroundStyle(.green)
                }
            }

            ForEach(Array(testResults.sorted { $0.dateTaken > $1.dateTaken }.prefix(5).enumerated()), id: \.offset) { _, result in
                HStack {
                    VStack(alignment: .leading, spacing: 2) {
                        Text("Week \(result.weekNumber)")
                            .font(.subheadline.weight(.medium))
                        Text(result.dateTaken.formatted(date: .abbreviated, time: .omitted))
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    }

                    Spacer()

                    Text("\(result.scorePercent)%")
                        .font(.title3.weight(.bold))
                        .foregroundStyle(result.scorePercent >= 90 ? .green : result.scorePercent >= 70 ? .orange : .red)
                }
                .padding(.vertical, 4)
            }
        }
        .padding()
        .background(.fill.quinary, in: RoundedRectangle(cornerRadius: 16))
    }

    // MARK: - Study Time Computed

    private var todayStudySeconds: Int {
        let today = DailyLog.todayString()
        return dailyLogs.first { $0.dateString == today }?.studySeconds ?? 0
    }

    private var totalStudySeconds: Int {
        dailyLogs.reduce(0) { $0 + $1.studySeconds } + studyTimer.currentSessionSeconds
    }

    private var weeklyStudySeconds: Int {
        weeklyStudyData.reduce(0) { $0 + $1.minutes } * 60
    }

    private var weeklyStudyData: [StudyDay] {
        let calendar = Calendar.current
        let today = calendar.startOfDay(for: Date())
        return (0..<7).reversed().map { daysAgo in
            let date = calendar.date(byAdding: .day, value: -daysAgo, to: today)!
            let dateStr = DailyLog.dateString(from: date)
            let seconds = dailyLogs.first { $0.dateString == dateStr }?.studySeconds ?? 0
            let dayLabel = daysAgo == 0 ? "Today" : Self.shortDayFormatter.string(from: date)
            return StudyDay(label: dayLabel, minutes: seconds / 60)
        }
    }

    private static let shortDayFormatter: DateFormatter = {
        let f = DateFormatter()
        f.dateFormat = "EEE"
        return f
    }()

    private func formatStudyTime(_ totalSeconds: Int) -> String {
        let hours = totalSeconds / 3600
        let minutes = (totalSeconds % 3600) / 60
        if hours > 0 {
            return "\(hours)h \(minutes)m"
        }
        return "\(minutes)m"
    }

    // MARK: - Computed

    private var recentLogs: [DailyLog] {
        return dailyLogs
            .filter { $0.reviewCount > 0 }
            .suffix(30)
            .reversed()
    }

    private var averageAccuracy: Int {
        let logsWithData = dailyLogs.filter { $0.reviewCount > 0 }
        guard !logsWithData.isEmpty else { return 0 }
        let total = logsWithData.reduce(0.0) { $0 + $1.accuracy }
        return Int(total / Double(logsWithData.count) * 100)
    }

    private func loadData() {
        let progress = ReviewStore.fetchOrCreateUserProgress(context: cloudModelContext)
        // Reset a stale streak before rendering so the dashboard never lies.
        progress.validateStreakIfStale(context: cloudModelContext)
        userProgress = progress
        let dailyDescriptor = FetchDescriptor<DailyLog>(
            sortBy: [SortDescriptor(\DailyLog.dateString, order: .reverse)]
        )
        dailyLogs = (try? cloudModelContext.fetch(dailyDescriptor)) ?? []
        testResults = (try? cloudModelContext.fetch(FetchDescriptor<TestResult>())) ?? []
        reviewCards = (try? cloudModelContext.fetch(FetchDescriptor<ReviewCard>())) ?? []
        try? cloudModelContext.save()
    }
}

// MARK: - Stat Card

private struct StatCard: View {
    let title: String
    let value: String
    let icon: String
    let color: Color

    var body: some View {
        VStack(spacing: 8) {
            Image(systemName: icon)
                .font(.title2)
                .foregroundStyle(color)

            Text(value)
                .font(.title2.bold().monospacedDigit())

            Text(title)
                .font(.caption)
                .foregroundStyle(.secondary)
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 16)
        .background(.fill.quinary, in: RoundedRectangle(cornerRadius: 14))
    }
}

private struct StudyDay: Identifiable {
    let label: String
    let minutes: Int
    var id: String { label }
}

#Preview {
    DashboardView()
        .environment(StudyTimerService())
        .modelContainer(for: [UserProgress.self, DailyLog.self, TestResult.self, ReviewCard.self], inMemory: true)
}
