package com.atridad.ascently.ui.screens

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.atridad.ascently.R
import com.atridad.ascently.data.model.AttemptResult
import com.atridad.ascently.data.model.ClimbType
import com.atridad.ascently.data.model.DifficultySystem
import com.atridad.ascently.ui.components.BarChart
import com.atridad.ascently.ui.components.BarChartDataPoint
import com.atridad.ascently.ui.components.SyncIndicator
import com.atridad.ascently.ui.viewmodel.ClimbViewModel
import com.atridad.ascently.utils.DateFormatUtils
import java.time.LocalDateTime

@Composable
fun AnalyticsScreen(viewModel: ClimbViewModel) {
    val sessions by viewModel.sessions.collectAsState()
    val problems by viewModel.problems.collectAsState()
    val attempts by viewModel.attempts.collectAsState()
    val gyms by viewModel.gyms.collectAsState()

    val gradeDistributionData = remember(sessions, problems, attempts) {
        calculateGradeDistribution(sessions, problems, attempts)
    }

    val favoriteGym = remember(sessions, gyms) {
        sessions.groupBy { it.gymId }.maxByOrNull { it.value.size }?.let { (gymId, sessionList) ->
            gyms.find { it.id == gymId }?.name to sessionList.size
        }
    }

    LazyColumn(
        modifier = Modifier.fillMaxSize().padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp),
    ) {
        item {
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(12.dp),
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_mountains),
                    contentDescription = "Ascently Logo",
                    modifier = Modifier.size(32.dp),
                    tint = MaterialTheme.colorScheme.primary,
                )
                Text(
                    text = "Analytics",
                    style = MaterialTheme.typography.headlineMedium,
                    fontWeight = FontWeight.Bold,
                    modifier = Modifier.weight(1f),
                )
                SyncIndicator(isSyncing = viewModel.syncService.isSyncing)
            }
        }

        // Overall Stats
        item {
            OverallStatsCard(
                totalSessions = sessions.size,
                totalProblems = problems.size,
                totalAttempts = attempts.size,
                totalGyms = gyms.size,
            )
        }

        // Grade Distribution Chart
        item {
            GradeDistributionChartCard(gradeDistributionData = gradeDistributionData)
        }

        // Favorite Gym
        item {
            FavoriteGymCard(
                gymName = favoriteGym?.first ?: "No sessions yet",
                sessionCount = favoriteGym?.second ?: 0,
            )
        }

        // Recent Activity
        item {
            val recentSessions = sessions.take(5)
            RecentActivityCard(recentSessions = recentSessions.size)
        }
    }
}

@Composable
fun OverallStatsCard(totalSessions: Int, totalProblems: Int, totalAttempts: Int, totalGyms: Int) {
    Card(modifier = Modifier.fillMaxWidth()) {
        Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
            Text(
                text = "Overall Stats",
                style = MaterialTheme.typography.titleMedium,
                fontWeight = FontWeight.Bold,
            )

            Spacer(modifier = Modifier.height(12.dp))

            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceEvenly,
            ) {
                StatItem(label = "Sessions", value = totalSessions.toString())
                StatItem(label = "Problems", value = totalProblems.toString())
                StatItem(label = "Attempts", value = totalAttempts.toString())
                StatItem(label = "Gyms", value = totalGyms.toString())
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun GradeDistributionChartCard(gradeDistributionData: List<GradeDistributionDataPoint>) {
    // Find all grading systems that have been used in the data
    val usedSystems =
        remember(gradeDistributionData) {
            gradeDistributionData.map { it.difficultySystem }.distinct()
        }

    var selectedSystem by
        remember(usedSystems) {
            mutableStateOf(usedSystems.firstOrNull() ?: DifficultySystem.V_SCALE)
        }
    var expanded by remember { mutableStateOf(false) }
    var showAllTime by remember { mutableStateOf(true) }

    Card(modifier = Modifier.fillMaxWidth()) {
        Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
            Text(
                text = "Grade Distribution",
                style = MaterialTheme.typography.titleMedium,
                fontWeight = FontWeight.Bold,
            )

            Spacer(modifier = Modifier.height(12.dp))

            // Toggles section
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically,
            ) {
                // Time period toggle
                Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                    // All Time button
                    FilterChip(
                        onClick = { showAllTime = true },
                        label = {
                            Text("All Time", style = MaterialTheme.typography.bodySmall)
                        },
                        selected = showAllTime,
                        colors =
                        FilterChipDefaults.filterChipColors(
                            selectedContainerColor =
                            MaterialTheme.colorScheme.primary,
                            selectedLabelColor = MaterialTheme.colorScheme.onPrimary,
                        ),
                    )

                    // 7 Days button
                    FilterChip(
                        onClick = { showAllTime = false },
                        label = { Text("7 Days", style = MaterialTheme.typography.bodySmall) },
                        selected = !showAllTime,
                        colors =
                        FilterChipDefaults.filterChipColors(
                            selectedContainerColor =
                            MaterialTheme.colorScheme.primary,
                            selectedLabelColor = MaterialTheme.colorScheme.onPrimary,
                        ),
                    )
                }

                // Scale selector dropdown
                if (usedSystems.size > 1) {
                    ExposedDropdownMenuBox(
                        expanded = expanded,
                        onExpandedChange = { expanded = !expanded },
                    ) {
                        OutlinedTextField(
                            value =
                            when (selectedSystem) {
                                DifficultySystem.V_SCALE -> "V-Scale"
                                DifficultySystem.FONT -> "Font"
                                DifficultySystem.YDS -> "YDS"
                                DifficultySystem.CUSTOM -> "Custom"
                            },
                            onValueChange = {},
                            readOnly = true,
                            trailingIcon = {
                                ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
                            },
                            modifier =
                            Modifier.menuAnchor(
                                type =
                                ExposedDropdownMenuAnchorType
                                    .PrimaryNotEditable,
                                enabled = true,
                            )
                                .width(120.dp),
                            textStyle = MaterialTheme.typography.bodyMedium,
                        )
                        ExposedDropdownMenu(
                            expanded = expanded,
                            onDismissRequest = { expanded = false },
                        ) {
                            usedSystems.forEach { system ->
                                DropdownMenuItem(
                                    text = {
                                        Text(
                                            when (system) {
                                                DifficultySystem.V_SCALE -> "V-Scale"
                                                DifficultySystem.FONT -> "Font"
                                                DifficultySystem.YDS -> "YDS"
                                                DifficultySystem.CUSTOM -> "Custom"
                                            },
                                        )
                                    },
                                    onClick = {
                                        selectedSystem = system
                                        expanded = false
                                    },
                                )
                            }
                        }
                    }
                }
            }

            Spacer(modifier = Modifier.height(12.dp))

            // Filter grade distribution data by selected scale and time period
            val filteredGradeData =
                remember(gradeDistributionData, selectedSystem, showAllTime) {
                    val systemFiltered =
                        gradeDistributionData.filter {
                            it.difficultySystem == selectedSystem
                        }

                    if (showAllTime) {
                        systemFiltered
                    } else {
                        // Filter for last 7 days
                        val sevenDaysAgo = LocalDateTime.now().minusDays(7)
                        systemFiltered.filter { dataPoint ->
                            try {
                                val attemptDate =
                                    DateFormatUtils.parseToLocalDateTime(dataPoint.date)
                                attemptDate?.isAfter(sevenDaysAgo) == true
                            } catch (_: Exception) {
                                // If date parsing fails, include the data point
                                true
                            }
                        }
                    }
                }

            if (filteredGradeData.isNotEmpty()) {
                // Group by grade and sum counts
                val gradeGroups =
                    filteredGradeData
                        .groupBy { it.grade }
                        .mapValues { (_, dataPoints) -> dataPoints.sumOf { it.count } }
                        .map { (grade, count) ->
                            val firstDataPoint =
                                filteredGradeData.first { it.grade == grade }
                            BarChartDataPoint(
                                label = grade,
                                value = count,
                                gradeNumeric = firstDataPoint.gradeNumeric,
                            )
                        }

                BarChart(data = gradeGroups, modifier = Modifier.fillMaxWidth().height(220.dp))

                Spacer(modifier = Modifier.height(8.dp))

                Text(
                    text =
                    "Successful climbs by ${when (selectedSystem) {
                        DifficultySystem.V_SCALE -> "V-grade"
                        DifficultySystem.FONT -> "Font grade"
                        DifficultySystem.YDS -> "YDS grade"
                        DifficultySystem.CUSTOM -> "custom grade"
                    }}",
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                )
            } else {
                Column(
                    modifier = Modifier.fillMaxWidth().height(220.dp),
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.Center,
                ) {
                    Icon(
                        painter = painterResource(id = R.drawable.ic_mountains),
                        contentDescription = "No data",
                        modifier = Modifier.size(48.dp),
                        tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f),
                    )

                    Spacer(modifier = Modifier.height(8.dp))

                    Text(
                        text = "No data available.",
                        style = MaterialTheme.typography.bodyMedium,
                        color = MaterialTheme.colorScheme.onSurfaceVariant,
                    )

                    Text(
                        text =
                        if (showAllTime) {
                            "Complete some climbs to see your grade distribution!"
                        } else {
                            "No climbs in the last 7 days"
                        },
                        style = MaterialTheme.typography.bodySmall,
                        color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f),
                    )
                }
            }
        }
    }
}

@Composable
fun FavoriteGymCard(gymName: String, sessionCount: Int) {
    Card(modifier = Modifier.fillMaxWidth()) {
        Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
            Text(
                text = "Favorite Gym",
                style = MaterialTheme.typography.titleMedium,
                fontWeight = FontWeight.Bold,
            )

            Spacer(modifier = Modifier.height(8.dp))

            Text(
                text = gymName,
                style = MaterialTheme.typography.titleLarge,
                fontWeight = FontWeight.Medium,
            )

            if (sessionCount > 0) {
                Text(
                    text = "$sessionCount sessions",
                    style = MaterialTheme.typography.bodyMedium,
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                )
            }
        }
    }
}

@Composable
fun RecentActivityCard(recentSessions: Int) {
    Card(modifier = Modifier.fillMaxWidth()) {
        Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
            Text(
                text = "Recent Activity",
                style = MaterialTheme.typography.titleMedium,
                fontWeight = FontWeight.Bold,
            )

            Spacer(modifier = Modifier.height(8.dp))

            Text(
                text =
                if (recentSessions > 0) {
                    "You've had $recentSessions recent sessions"
                } else {
                    "No recent activity"
                },
                style = MaterialTheme.typography.bodyMedium,
            )
        }
    }
}

data class GradeDistributionDataPoint(
    val date: String,
    val grade: String,
    val gradeNumeric: Int,
    val count: Int,
    val climbType: ClimbType,
    val difficultySystem: DifficultySystem,
)

fun calculateGradeDistribution(
    sessions: List<com.atridad.ascently.data.model.ClimbSession>,
    problems: List<com.atridad.ascently.data.model.Problem>,
    attempts: List<com.atridad.ascently.data.model.Attempt>,
): List<GradeDistributionDataPoint> {
    if (sessions.isEmpty() || problems.isEmpty() || attempts.isEmpty()) {
        return emptyList()
    }

    // Get all successful attempts
    val successfulAttempts =
        attempts.filter {
            it.result == AttemptResult.SUCCESS || it.result == AttemptResult.FLASH
        }

    if (successfulAttempts.isEmpty()) {
        return emptyList()
    }

    // Map attempts to problems and create grade distribution data
    val gradeDistribution = mutableMapOf<String, GradeDistributionDataPoint>()

    successfulAttempts.forEach { attempt ->
        val problem = problems.find { it.id == attempt.problemId }
        val session = sessions.find { it.id == attempt.sessionId }

        if (problem != null && session != null) {
            val key = "${problem.difficulty.system.name}-${problem.difficulty.grade}"

            val existing = gradeDistribution[key]
            if (existing != null) {
                gradeDistribution[key] = existing.copy(count = existing.count + 1)
            } else {
                gradeDistribution[key] =
                    GradeDistributionDataPoint(
                        date = attempt.timestamp,
                        grade = problem.difficulty.grade,
                        gradeNumeric =
                        gradeToNumeric(
                            problem.difficulty.system,
                            problem.difficulty.grade,
                        ),
                        count = 1,
                        climbType = problem.climbType,
                        difficultySystem = problem.difficulty.system,
                    )
            }
        }
    }

    return gradeDistribution.values.toList()
}

fun gradeToNumeric(system: DifficultySystem, grade: String): Int {
    return when (system) {
        DifficultySystem.V_SCALE -> {
            when (grade) {
                "VB" -> 0
                else -> grade.removePrefix("V").toIntOrNull() ?: 0
            }
        }
        DifficultySystem.FONT -> {
            when (grade) {
                "3" -> 3
                "4A" -> 4
                "4B" -> 5
                "4C" -> 6
                "5A" -> 7
                "5B" -> 8
                "5C" -> 9
                "6A" -> 10
                "6A+" -> 11
                "6B" -> 12
                "6B+" -> 13
                "6C" -> 14
                "6C+" -> 15
                "7A" -> 16
                "7A+" -> 17
                "7B" -> 18
                "7B+" -> 19
                "7C" -> 20
                "7C+" -> 21
                "8A" -> 22
                "8A+" -> 23
                "8B" -> 24
                "8B+" -> 25
                "8C" -> 26
                "8C+" -> 27
                else -> 0
            }
        }
        DifficultySystem.YDS -> {
            when (grade) {
                "5.0" -> 50
                "5.1" -> 51
                "5.2" -> 52
                "5.3" -> 53
                "5.4" -> 54
                "5.5" -> 55
                "5.6" -> 56
                "5.7" -> 57
                "5.8" -> 58
                "5.9" -> 59
                "5.10a" -> 60
                "5.10b" -> 61
                "5.10c" -> 62
                "5.10d" -> 63
                "5.11a" -> 64
                "5.11b" -> 65
                "5.11c" -> 66
                "5.11d" -> 67
                "5.12a" -> 68
                "5.12b" -> 69
                "5.12c" -> 70
                "5.12d" -> 71
                "5.13a" -> 72
                "5.13b" -> 73
                "5.13c" -> 74
                "5.13d" -> 75
                "5.14a" -> 76
                "5.14b" -> 77
                "5.14c" -> 78
                "5.14d" -> 79
                "5.15a" -> 80
                "5.15b" -> 81
                "5.15c" -> 82
                "5.15d" -> 83
                else -> 0
            }
        }
        DifficultySystem.CUSTOM -> {
            // Custom grades are numeric strings, so parse them directly
            grade.toIntOrNull() ?: 0
        }
    }
}
