package com.fabledsword.minstrel.settings.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle

private const val GIB: Long = 1024L * 1024 * 1024
private const val MIB: Long = 1024L * 1024
private const val KIB: Long = 1024L

private val CAP_OPTIONS: List<Pair<Long, String>> = listOf(
    1L * GIB to "1 GB",
    5L * GIB to "5 GB",
    10L * GIB to "10 GB",
    25L * GIB to "25 GB",
    0L to "Unlimited",
)

@Composable
fun StorageCard(viewModel: StorageViewModel = hiltViewModel()) {
    val state by viewModel.state.collectAsStateWithLifecycle()
    var showClearConfirm by remember { mutableStateOf(false) }
    ElevatedCard(modifier = Modifier.fillMaxWidth()) {
        Column(
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            Text(
                text = "Storage",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onSurface,
            )
            UsageRow(usedBytes = state.usedBytes)
            // Per-bucket caps + prefetch toggle + cache-liked toggle
            // intentionally omitted in v1. The underlying systems
            // (per-bucket SimpleCache eviction, MetadataPrefetcher,
            // pin-on-like flow) don't exist on Android yet — surfacing
            // controls that silently do nothing is worse than hiding
            // them. Only the rolling cap is wired
            // (PlayerFactory.kt:43-47 uses rollingCapBytes only); the
            // Liked cap was a no-op. CacheSettings fields stay
            // persisted so the controls return when the systems land.
            CapDropdown(
                label = "Cache limit",
                value = state.settings.rollingCapBytes,
                onSet = viewModel::setRollingCapBytes,
            )
            Text(
                text = "Takes effect on the next app launch.",
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
            )
            StorageActions(
                isSyncing = state.isSyncing,
                isClearing = state.isClearing,
                onSync = viewModel::syncNow,
                onClear = { showClearConfirm = true },
            )
        }
    }
    if (showClearConfirm) {
        ClearCacheConfirmDialog(
            onConfirm = {
                showClearConfirm = false
                viewModel.clearCache()
            },
            onDismiss = { showClearConfirm = false },
        )
    }
}

@Composable
private fun UsageRow(usedBytes: Long) {
    Row(modifier = Modifier.fillMaxWidth()) {
        Text(
            text = "Used",
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
            modifier = Modifier.weight(1f),
        )
        Text(
            text = formatBytes(usedBytes),
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurface,
        )
    }
}

@Composable
private fun CapDropdown(label: String, value: Long, onSet: (Long) -> Unit) {
    val selectedLabel = CAP_OPTIONS.firstOrNull { it.first == value }?.second
        ?: formatBytes(value)
    LabeledDropdown(
        label = label,
        selectedLabel = selectedLabel,
        options = CAP_OPTIONS,
        onSelect = onSet,
    )
}

/**
 * Label on the left, button-with-current-value on the right that opens
 * a DropdownMenu of [options]. Used by the cap selectors.
 */
@Composable
private fun <T> LabeledDropdown(
    label: String,
    selectedLabel: String,
    options: List<Pair<T, String>>,
    onSelect: (T) -> Unit,
) {
    var expanded by remember { mutableStateOf(false) }
    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Text(
            text = label,
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
            modifier = Modifier.weight(1f),
        )
        OutlinedButton(onClick = { expanded = true }) {
            Text(selectedLabel)
            DropdownMenu(
                expanded = expanded,
                onDismissRequest = { expanded = false },
            ) {
                options.forEach { (value, name) ->
                    DropdownMenuItem(
                        text = { Text(name) },
                        onClick = {
                            expanded = false
                            onSelect(value)
                        },
                    )
                }
            }
        }
    }
}

@Composable
private fun StorageActions(
    isSyncing: Boolean,
    isClearing: Boolean,
    onSync: () -> Unit,
    onClear: () -> Unit,
) {
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(8.dp),
    ) {
        OutlinedButton(
            onClick = onClear,
            enabled = !isClearing,
        ) {
            if (isClearing) {
                CircularProgressIndicator(
                    modifier = Modifier.size(16.dp),
                    strokeWidth = 2.dp,
                )
                Spacer(Modifier.size(8.dp))
            }
            Text(if (isClearing) "Clearing…" else "Clear cache")
        }
        OutlinedButton(
            onClick = onSync,
            enabled = !isSyncing,
        ) {
            if (isSyncing) {
                CircularProgressIndicator(
                    modifier = Modifier.size(16.dp),
                    strokeWidth = 2.dp,
                )
                Spacer(Modifier.size(8.dp))
            }
            Text(if (isSyncing) "Syncing…" else "Sync now")
        }
    }
}

@Composable
private fun ClearCacheConfirmDialog(onConfirm: () -> Unit, onDismiss: () -> Unit) {
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Clear cache?") },
        text = {
            Text(
                "This deletes all cached audio. The next play of any track " +
                    "re-downloads from the server.",
            )
        },
        confirmButton = {
            Button(
                onClick = onConfirm,
                colors = ButtonDefaults.buttonColors(
                    containerColor = MaterialTheme.colorScheme.error,
                    contentColor = MaterialTheme.colorScheme.onError,
                ),
            ) { Text("Clear") }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) { Text("Cancel") }
        },
    )
}

private fun formatBytes(n: Long): String {
    if (n <= 0L) return "0 B"
    return when {
        n < KIB -> "$n B"
        n < MIB -> "${"%.1f".format(n.toDouble() / KIB)} KB"
        n < GIB -> "${"%.1f".format(n.toDouble() / MIB)} MB"
        else -> "${"%.2f".format(n.toDouble() / GIB)} GB"
    }
}
