package dev.privacyllc.period.feature.settings

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.clickable
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.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
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.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import dev.privacyllc.period.R
import dev.privacyllc.period.designsystem.PeriodTheme

/**
 * Settings, structured as PRODUCT_PLAN.md §36 specifies.
 *
 * ## Why sections appear as they are built
 *
 * §36 describes the whole tree — Cycle, Notifications, Privacy & Security,
 * Appearance, Premium, About. This screen shows only the sections that have
 * something behind them, and **a row for an unbuilt feature is absent rather
 * than disabled**.
 *
 * That is deliberate. A greyed-out "Export My Data" is a promise with no
 * delivery date, and in a privacy app specifically it is worse than silence: a
 * user who sees a disabled Delete My Data has been told the feature exists and
 * that they may not have it. A section that is not there yet is simply not
 * there yet, and the tracker is where the plan lives.
 *
 * So Privacy & Security arrives with #34 to #37, Appearance with Batch 08's
 * theme control, and Premium with Batch 07.
 */
@Composable
fun SettingsScreen(
    onOpenNotifications: () -> Unit,
    viewModel: PrivacyViewModel? = hiltViewModel(),
) {
    val deletion = viewModel?.deletion?.collectAsStateWithLifecycle()?.value ?: DeletionState.IDLE
    var confirming by remember { mutableStateOf(false) }

    Column(
        Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
            .padding(horizontal = 16.dp, vertical = 8.dp),
    ) {
        SectionHeader("Notifications")
        SettingsRow(
            title = "Reminders and privacy",
            subtitle = "What a reminder says, and what it withholds",
            onClick = onOpenNotifications,
        )

        Spacer(Modifier.height(8.dp))
        SectionHeader("Privacy & Security")
        SettingsRow(
            title = "Delete my data",
            subtitle = "Erase every period, spotting and prediction record",
            onClick = { confirming = true },
        )

        Spacer(Modifier.height(8.dp))
        SectionHeader("About")
        ExpandableRow(
            title = "How predictions work",
            body = "The app learns from the period dates you confirm. It weighs your " +
                "recent cycles more heavily than old ones, and it measures how much " +
                "they vary — that variation is what sets the window and the confidence " +
                "label, so a steady cycle gets a tight window and an irregular one " +
                "gets an honest wide one.\n\n" +
                "It never presents a bare date as fact, and until there is enough of " +
                "your own history it says so rather than falling back on a generic " +
                "28-day cycle.",
        )
        ExpandableRow(
            title = "Fertility disclaimer",
            body = stringResource(R.string.fertility_disclaimer),
        )
        StaticRow(title = "Version", value = versionName())
    }

    if (confirming) {
        DeleteConfirmation(
            onConfirm = {
                confirming = false
                viewModel?.deleteEverything()
            },
            onDismiss = { confirming = false },
        )
    }

    when (deletion) {
        DeletionState.DONE -> ResultDialog(
            title = "Your data is deleted",
            body = "Every period, spotting and prediction record has been erased " +
                "from this device. Your reminder settings are unchanged.",
            onDismiss = { viewModel?.acknowledge() },
        )
        DeletionState.FAILED -> ResultDialog(
            title = "Nothing was deleted",
            body = "Something went wrong and your data is still here. Try again, " +
                "and if it keeps failing your records are intact.",
            onDismiss = { viewModel?.acknowledge() },
        )
        else -> Unit
    }
}

/**
 * §45 wants this "clear and irreversible after confirmation", so the dialog
 * does three things a default one would not.
 *
 * It says what is destroyed **and what is kept** — a user deleting their history
 * should not have to wonder whether their notification privacy went with it. It
 * labels the button with the action rather than "OK", because "OK" to a question
 * nobody read is how accidental deletions happen. And it does not offer an undo:
 * that is the point of the control, not an omission.
 */
@Composable
private fun DeleteConfirmation(onConfirm: () -> Unit, onDismiss: () -> Unit) {
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Delete your data?") },
        text = {
            Text(
                "This erases every period, spotting and prediction record on this " +
                    "device. Your reminder and privacy settings are kept.\n\n" +
                    "This cannot be undone.",
            )
        },
        confirmButton = {
            TextButton(onClick = onConfirm) {
                Text("Delete my data", color = MaterialTheme.colorScheme.error)
            }
        },
        dismissButton = { TextButton(onClick = onDismiss) { Text("Keep my data") } },
    )
}

@Composable
private fun ResultDialog(title: String, body: String, onDismiss: () -> Unit) {
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text(title) },
        text = { Text(body) },
        confirmButton = { TextButton(onClick = onDismiss) { Text("Done") } },
    )
}

/**
 * The installed version, read from the package manager rather than a
 * `BuildConfig` constant — so it reports what is actually on the device, which
 * is the number a person reads out when something is wrong.
 */
@Composable
private fun versionName(): String {
    val context = LocalContext.current
    return remember(context) {
        runCatching {
            context.packageManager.getPackageInfo(context.packageName, 0).versionName
        }.getOrNull() ?: "unknown"
    }
}

@Composable
private fun SectionHeader(text: String) {
    Spacer(Modifier.height(16.dp))
    Text(
        text,
        style = MaterialTheme.typography.titleSmall,
        color = MaterialTheme.colorScheme.primary,
    )
    Spacer(Modifier.height(4.dp))
}

@Composable
private fun SettingsRow(title: String, subtitle: String, onClick: () -> Unit) {
    Column(
        Modifier
            .fillMaxWidth()
            .clickable(onClick = onClick)
            .padding(vertical = 12.dp),
    ) {
        Text(title, style = MaterialTheme.typography.bodyLarge)
        Text(
            subtitle,
            style = MaterialTheme.typography.bodySmall,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
        )
    }
    HorizontalDivider()
}

/**
 * A row that opens its own explanation.
 *
 * Expanding in place rather than navigating: every one of these is a paragraph,
 * and a destination that holds one paragraph is a back-stack entry the user has
 * to spend to read two sentences.
 */
@Composable
private fun ExpandableRow(title: String, body: String) {
    var open by remember { mutableStateOf(false) }
    Column(
        Modifier
            .fillMaxWidth()
            .clickable { open = !open }
            .padding(vertical = 12.dp),
    ) {
        Row(
            Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween,
            verticalAlignment = Alignment.CenterVertically,
        ) {
            Text(title, style = MaterialTheme.typography.bodyLarge)
            // Text rather than a chevron: it states the action, and TalkBack
            // reads it without needing a content description nobody wrote.
            Text(
                if (open) "Hide" else "Show",
                style = MaterialTheme.typography.labelMedium,
                color = MaterialTheme.colorScheme.primary,
            )
        }
        AnimatedVisibility(open) {
            Text(
                body,
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
                modifier = Modifier.padding(top = 8.dp),
            )
        }
    }
    HorizontalDivider()
}

@Composable
private fun StaticRow(title: String, value: String) {
    Row(
        Modifier
            .fillMaxWidth()
            .padding(vertical = 12.dp),
        horizontalArrangement = Arrangement.SpaceBetween,
    ) {
        Text(title, style = MaterialTheme.typography.bodyLarge)
        Text(
            value,
            style = MaterialTheme.typography.bodyLarge,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
        )
    }
}

@Preview(name = "Settings · light", showBackground = true)
@Preview(
    name = "Settings · dark",
    showBackground = true,
    uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES,
)
@Composable
private fun PreviewSettingsRoot() = PeriodTheme {
    SettingsScreen(onOpenNotifications = {}, viewModel = null)
}
