@file:Suppress("TooManyFunctions") // Settings screen + per-card helper composables

package com.fabledsword.minstrel.settings.ui

import androidx.compose.foundation.clickable
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
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.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import com.composables.icons.lucide.ChevronRight
import com.composables.icons.lucide.ListMusic
import com.composables.icons.lucide.LogOut
import com.composables.icons.lucide.Lucide
import com.composables.icons.lucide.Shield
import com.fabledsword.minstrel.BuildConfig
import com.fabledsword.minstrel.nav.Admin
import com.fabledsword.minstrel.nav.Requests
import com.fabledsword.minstrel.nav.Settings as SettingsRoute
import com.fabledsword.minstrel.nav.ServerUrl
import com.fabledsword.minstrel.shared.widgets.ShellContentWindowInsets
import com.fabledsword.minstrel.shared.widgets.MinstrelTopAppBar
import com.fabledsword.minstrel.theme.ThemeMode
import com.fabledsword.minstrel.theme.ThemePreferenceViewModel
import com.fabledsword.minstrel.update.data.InstallStage
import com.fabledsword.minstrel.update.data.isBusy

@Composable
fun SettingsScreen(
    navController: NavHostController,
    viewModel: SettingsViewModel = hiltViewModel(),
    themeVm: ThemePreferenceViewModel = hiltViewModel(),
) {
    val state by viewModel.state.collectAsStateWithLifecycle()
    val themeMode by themeVm.themeMode.collectAsStateWithLifecycle()
    var showSignOutConfirm by remember { mutableStateOf(false) }

    LaunchedEffect(state.signedOut) {
        if (state.signedOut) {
            navController.navigate(ServerUrl) {
                popUpTo(0) { inclusive = true }
            }
            viewModel.consumeSignedOut()
        }
    }

    Scaffold(
        contentWindowInsets = ShellContentWindowInsets,
        modifier = Modifier.fillMaxSize(),
        topBar = {
            MinstrelTopAppBar(
                title = "Settings",
                navController = navController,
                currentRouteName = SettingsRoute::class.qualifiedName,
            )
        },
    ) { inner ->
        SettingsList(
            inner = inner,
            state = state,
            themeMode = themeMode,
            onPickTheme = themeVm::setThemeMode,
            onNavToRequests = { navController.navigate(Requests) },
            onNavToAdmin = { navController.navigate(Admin) },
            onToggleDiagnostics = viewModel::setDiagnosticsOptOut,
            onSignOutClick = { showSignOutConfirm = true },
        )
    }
    if (showSignOutConfirm) {
        SignOutConfirmDialog(
            onConfirm = {
                showSignOutConfirm = false
                viewModel.signOut()
            },
            onDismiss = { showSignOutConfirm = false },
        )
    }
}

@Composable
private fun SettingsList(
    inner: androidx.compose.foundation.layout.PaddingValues,
    state: SettingsState,
    themeMode: ThemeMode,
    onPickTheme: (ThemeMode) -> Unit,
    onNavToRequests: () -> Unit,
    onNavToAdmin: () -> Unit,
    onToggleDiagnostics: (Boolean) -> Unit,
    onSignOutClick: () -> Unit,
) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(inner)
            .verticalScroll(rememberScrollState())
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp),
    ) {
        AccountCard(
            username = state.username,
            isAdmin = state.isAdmin,
            serverUrl = state.serverUrl,
        )
        NavTile(
            icon = Lucide.ListMusic,
            title = "My requests",
            subtitle = "Track what you've asked Minstrel to add",
            onClick = onNavToRequests,
        )
        if (state.isAdmin) {
            NavTile(
                icon = Lucide.Shield,
                title = "Admin",
                subtitle = "Manage requests, quarantine, and users",
                onClick = onNavToAdmin,
            )
        }
        ProfileCard()
        PasswordCard()
        ListenBrainzCard()
        if (state.diagnosticsEnabledByAdmin) {
            DiagnosticsCard(
                optOut = state.diagnosticsOptOut,
                onToggle = onToggleDiagnostics,
            )
        }
        AppearanceCard(themeMode = themeMode, onPick = onPickTheme)
        StorageCard()
        AboutCard()
        SignOutButton(isSigningOut = state.isSigningOut, onSignOut = onSignOutClick)
    }
}

@Composable
private fun SignOutConfirmDialog(onConfirm: () -> Unit, onDismiss: () -> Unit) {
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Sign out?") },
        text = {
            Text(
                "Sign out of this server? Your downloaded music and " +
                    "settings on this device will be removed.",
            )
        },
        confirmButton = {
            Button(
                onClick = onConfirm,
                colors = ButtonDefaults.buttonColors(
                    containerColor = MaterialTheme.colorScheme.errorContainer,
                    contentColor = MaterialTheme.colorScheme.onErrorContainer,
                ),
            ) { Text("Sign out") }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) { Text("Cancel") }
        },
    )
}

@Composable
private fun NavTile(
    icon: ImageVector,
    title: String,
    subtitle: String,
    onClick: () -> Unit,
) {
    ElevatedCard(
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = onClick),
    ) {
        Row(
            modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            Icon(
                imageVector = icon,
                contentDescription = null,
                tint = MaterialTheme.colorScheme.onSurface,
            )
            Spacer(Modifier.size(16.dp))
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = title,
                    style = MaterialTheme.typography.titleMedium,
                    color = MaterialTheme.colorScheme.onSurface,
                )
                Text(
                    text = subtitle,
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                )
            }
            Icon(
                imageVector = Lucide.ChevronRight,
                contentDescription = null,
                tint = MaterialTheme.colorScheme.onSurfaceVariant,
            )
        }
    }
}

@Composable
private fun AccountCard(username: String, isAdmin: Boolean, serverUrl: String) {
    ElevatedCard(modifier = Modifier.fillMaxWidth()) {
        Column(
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(4.dp),
        ) {
            Text(
                text = "Account",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onSurface,
            )
            val adminTag = if (isAdmin) " · admin" else ""
            Text(
                text = when {
                    username.isEmpty() -> "Signed in"
                    else -> "Signed in as $username$adminTag"
                },
                style = MaterialTheme.typography.bodyMedium,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
            )
            Spacer(Modifier.height(8.dp))
            Text(
                text = "Server",
                style = MaterialTheme.typography.titleSmall,
                color = MaterialTheme.colorScheme.onSurface,
            )
            Text(
                text = serverUrl,
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
            )
        }
    }
}

// Shown only while an admin has enabled debug mode on this account. Lets
// the user turn reporting OFF on this device (battery/privacy) without
// touching the account flag. Checked = reporting on = NOT opted out.
@Composable
private fun DiagnosticsCard(optOut: Boolean, onToggle: (Boolean) -> Unit) {
    ElevatedCard(modifier = Modifier.fillMaxWidth()) {
        Column(
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            Text(
                text = "Diagnostics",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onSurface,
            )
            Row(verticalAlignment = Alignment.CenterVertically) {
                Column(modifier = Modifier.weight(1f)) {
                    Text(
                        text = "Send diagnostic reports",
                        style = MaterialTheme.typography.bodyLarge,
                        color = MaterialTheme.colorScheme.onSurface,
                    )
                    Text(
                        text = "Your admin enabled debug mode to investigate an " +
                            "issue. This device streams connectivity and playback " +
                            "diagnostics. Turn off any time.",
                        style = MaterialTheme.typography.bodySmall,
                        color = MaterialTheme.colorScheme.onSurfaceVariant,
                    )
                }
                Spacer(Modifier.size(12.dp))
                Switch(
                    checked = !optOut,
                    onCheckedChange = { checked -> onToggle(!checked) },
                )
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun AppearanceCard(themeMode: ThemeMode, onPick: (ThemeMode) -> Unit) {
    val options = ThemeMode.entries
    ElevatedCard(modifier = Modifier.fillMaxWidth()) {
        Column(
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            Text(
                text = "Appearance",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onSurface,
            )
            Text(
                text = "System follows your device setting.",
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
            )
            SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
                options.forEachIndexed { index, mode ->
                    SegmentedButton(
                        selected = mode == themeMode,
                        onClick = { onPick(mode) },
                        shape = SegmentedButtonDefaults.itemShape(
                            index = index,
                            count = options.size,
                        ),
                    ) { Text(displayName(mode)) }
                }
            }
        }
    }
}

private fun displayName(mode: ThemeMode): String = when (mode) {
    ThemeMode.SYSTEM -> "System"
    ThemeMode.LIGHT -> "Light"
    ThemeMode.DARK -> "Dark"
}

@Composable
private fun AboutCard(viewModel: AboutCardViewModel = hiltViewModel()) {
    val state by viewModel.state.collectAsStateWithLifecycle()
    ElevatedCard(modifier = Modifier.fillMaxWidth()) {
        Column(
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            Text(
                text = "About",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onSurface,
            )
            Text(
                text = "Installed: Minstrel ${state.installedVersion} " +
                    "(${BuildConfig.VERSION_CODE})",
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
            )
            UpdateControls(state = state, viewModel = viewModel)
        }
    }
}

@Composable
private fun UpdateControls(state: AboutUiState, viewModel: AboutCardViewModel) {
    UpdateCheckLine(result = state.result)
    Button(
        onClick = viewModel::checkForUpdates,
        enabled = !state.isChecking && !state.installStage.isBusy(),
        modifier = Modifier.fillMaxWidth(),
    ) {
        if (state.isChecking) {
            ButtonSpinner()
        }
        Text(if (state.isChecking) "Checking…" else "Check for updates")
    }
    val available = state.result as? UpdateCheckResult.UpdateAvailable
    if (available != null) {
        InstallButton(
            version = available.info.version,
            stage = state.installStage,
            onClick = { viewModel.install(available.info) },
        )
    }
    if (state.installMessage != null) {
        Text(
            text = state.installMessage,
            style = MaterialTheme.typography.bodySmall,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
        )
    }
}

@Composable
private fun InstallButton(version: String, stage: InstallStage, onClick: () -> Unit) {
    Button(
        onClick = onClick,
        enabled = !stage.isBusy(),
        modifier = Modifier.fillMaxWidth(),
    ) {
        if (stage.isBusy()) {
            ButtonSpinner()
        }
        Text(
            when (stage) {
                InstallStage.DOWNLOADING -> "Downloading…"
                InstallStage.INSTALLING -> "Installing…"
                else -> "Install $version"
            },
        )
    }
}

@Composable
private fun ButtonSpinner() {
    CircularProgressIndicator(
        modifier = Modifier.size(16.dp),
        strokeWidth = 2.dp,
        color = MaterialTheme.colorScheme.onPrimary,
    )
    Spacer(Modifier.size(8.dp))
}

@Composable
private fun UpdateCheckLine(result: UpdateCheckResult) {
    val text = when (result) {
        UpdateCheckResult.Idle -> return
        UpdateCheckResult.Latest -> "You're on the latest version."
        is UpdateCheckResult.UpdateAvailable ->
            "Update available: ${result.info.version}"
        is UpdateCheckResult.Error -> "Couldn't check: ${result.message}"
    }
    Text(
        text = text,
        style = MaterialTheme.typography.bodySmall,
        color = MaterialTheme.colorScheme.onSurfaceVariant,
    )
}

@Composable
private fun SignOutButton(isSigningOut: Boolean, onSignOut: () -> Unit) {
    Button(
        onClick = onSignOut,
        enabled = !isSigningOut,
        modifier = Modifier.fillMaxWidth(),
        colors = ButtonDefaults.buttonColors(
            containerColor = MaterialTheme.colorScheme.errorContainer,
            contentColor = MaterialTheme.colorScheme.onErrorContainer,
        ),
    ) {
        if (isSigningOut) {
            CircularProgressIndicator(
                modifier = Modifier.size(20.dp),
                color = MaterialTheme.colorScheme.onErrorContainer,
                strokeWidth = 2.dp,
            )
        } else {
            Box(modifier = Modifier.padding(end = 4.dp)) {
                Icon(Lucide.LogOut, contentDescription = null)
            }
            Text("Sign out")
        }
    }
}
