@file:Suppress("TooManyFunctions") // Compose screen + private helper composables and dialogs

package com.fabledsword.minstrel.admin.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.layout.size
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import com.composables.icons.lucide.Lucide
import com.composables.icons.lucide.Copy
import com.composables.icons.lucide.KeyRound
import com.composables.icons.lucide.Plus
import com.composables.icons.lucide.Trash2
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import android.content.ClipData
import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.LocalClipboard
import com.fabledsword.minstrel.models.Invite
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.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.PasswordVisualTransformation
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.fabledsword.minstrel.models.AdminUserRef
import com.fabledsword.minstrel.nav.AdminUsers
import com.fabledsword.minstrel.shared.widgets.ShellContentWindowInsets
import com.fabledsword.minstrel.shared.widgets.MinstrelTopAppBar
import com.fabledsword.minstrel.shared.widgets.PullToRefreshScaffold
import kotlinx.coroutines.launch

@Composable
fun AdminUsersScreen(
    navController: NavHostController,
    viewModel: AdminUsersViewModel = hiltViewModel(),
    invitesViewModel: AdminInvitesViewModel = hiltViewModel(),
) {
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    val invitesState by invitesViewModel.state.collectAsStateWithLifecycle()
    var resetPasswordFor by remember { mutableStateOf<AdminUserRef?>(null) }
    var deleteCandidate by remember { mutableStateOf<AdminUserRef?>(null) }
    var showGenerateInvite by remember { mutableStateOf(false) }
    var generatedInvite by remember { mutableStateOf<Invite?>(null) }
    LaunchedEffect(Unit) {
        invitesViewModel.created.collect { invite ->
            generatedInvite = invite
        }
    }

    AdminUsersScaffold(
        navController = navController,
        usersState = state,
        invitesState = invitesState,
        onRefresh = {
            viewModel.refresh().join()
            invitesViewModel.refresh()
        },
        onSetAdmin = viewModel::setAdmin,
        onSetAutoApprove = viewModel::setAutoApprove,
        onAskResetPassword = { resetPasswordFor = it },
        onAskDelete = { deleteCandidate = it },
        onAskGenerateInvite = { showGenerateInvite = true },
        onRevokeInvite = invitesViewModel::revoke,
    )

    PendingDialogs(
        resetPasswordFor = resetPasswordFor,
        deleteCandidate = deleteCandidate,
        onClearReset = { resetPasswordFor = null },
        onClearDelete = { deleteCandidate = null },
        onConfirmReset = viewModel::resetPassword,
        onConfirmDelete = viewModel::delete,
    )

    if (showGenerateInvite) {
        GenerateInviteDialog(
            onDismiss = { showGenerateInvite = false },
            onConfirm = { note ->
                invitesViewModel.generate(note)
                showGenerateInvite = false
            },
        )
    }
    generatedInvite?.let { invite ->
        GeneratedInviteDialog(
            invite = invite,
            onDismiss = { generatedInvite = null },
        )
    }
}

@Composable
private fun AdminUsersScaffold(
    navController: NavHostController,
    usersState: AdminUsersUiState,
    invitesState: AdminInvitesUiState,
    onRefresh: suspend () -> Unit,
    onSetAdmin: (String, Boolean) -> Unit,
    onSetAutoApprove: (String, Boolean) -> Unit,
    onAskResetPassword: (AdminUserRef) -> Unit,
    onAskDelete: (AdminUserRef) -> Unit,
    onAskGenerateInvite: () -> Unit,
    onRevokeInvite: (String) -> Unit,
) {
    Scaffold(
        contentWindowInsets = ShellContentWindowInsets,
        modifier = Modifier.fillMaxSize(),
        topBar = {
            MinstrelTopAppBar(
                title = "Admin · Users",
                navController = navController,
                currentRouteName = AdminUsers::class.qualifiedName,
                onBack = { navController.popBackStack() },
            )
        },
    ) { inner ->
        PullToRefreshScaffold(
            onRefresh = onRefresh,
            modifier = Modifier.fillMaxSize().padding(inner),
        ) {
            LazyColumn(modifier = Modifier.fillMaxSize()) {
                item { SectionHeader("Users") }
                usersSection(
                    state = usersState,
                    onSetAdmin = onSetAdmin,
                    onSetAutoApprove = onSetAutoApprove,
                    onAskResetPassword = onAskResetPassword,
                    onAskDelete = onAskDelete,
                )
                item { HorizontalDivider() }
                item {
                    SectionHeader(
                        label = "Invites",
                        trailing = {
                            TextButton(onClick = onAskGenerateInvite) {
                                Icon(
                                    Lucide.Plus,
                                    contentDescription = null,
                                    modifier = Modifier.size(16.dp),
                                )
                                Text("Generate")
                            }
                        },
                    )
                }
                invitesSection(state = invitesState, onRevoke = onRevokeInvite)
            }
        }
    }
}

@Composable
private fun SectionHeader(label: String, trailing: (@Composable () -> Unit)? = null) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 8.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Text(
            text = label,
            style = MaterialTheme.typography.titleMedium,
            color = MaterialTheme.colorScheme.onSurface,
            modifier = Modifier.weight(1f),
        )
        if (trailing != null) trailing()
    }
}

private fun androidx.compose.foundation.lazy.LazyListScope.usersSection(
    state: AdminUsersUiState,
    onSetAdmin: (String, Boolean) -> Unit,
    onSetAutoApprove: (String, Boolean) -> Unit,
    onAskResetPassword: (AdminUserRef) -> Unit,
    onAskDelete: (AdminUserRef) -> Unit,
) {
    when (state) {
        AdminUsersUiState.Loading -> item { CenteredHint("Loading users…") }
        AdminUsersUiState.Empty -> item { CenteredHint("No registered users.") }
        is AdminUsersUiState.Error -> item { CenteredHint(state.message) }
        is AdminUsersUiState.Success -> items(items = state.users, key = { it.id }) { user ->
            UserRow(
                user = user,
                onSetAdmin = { onSetAdmin(user.id, it) },
                onSetAutoApprove = { onSetAutoApprove(user.id, it) },
                onResetPassword = { onAskResetPassword(user) },
                onDelete = { onAskDelete(user) },
            )
            HorizontalDivider()
        }
    }
}

private fun androidx.compose.foundation.lazy.LazyListScope.invitesSection(
    state: AdminInvitesUiState,
    onRevoke: (String) -> Unit,
) {
    when {
        state.isLoading -> item { CenteredHint("Loading invites…") }
        state.invites.isEmpty() -> item {
            CenteredHint("No active invites. Use Generate to create one.")
        }
        else -> items(items = state.invites, key = { it.token }) { invite ->
            InviteRow(invite = invite, onRevoke = { onRevoke(invite.token) })
            HorizontalDivider()
        }
    }
}

@Composable
private fun CenteredHint(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.bodyMedium,
        color = MaterialTheme.colorScheme.onSurfaceVariant,
        modifier = Modifier.fillMaxWidth().padding(16.dp),
    )
}

@Composable
private fun InviteRow(invite: Invite, onRevoke: () -> Unit) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 12.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Column(modifier = Modifier.weight(1f)) {
            Text(
                text = invite.token,
                style = MaterialTheme.typography.bodyLarge,
                color = MaterialTheme.colorScheme.onSurface,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
            )
            val subtitle = buildString {
                if (!invite.note.isNullOrEmpty()) {
                    append(invite.note)
                    append(" · ")
                }
                append(if (invite.isRedeemed) "redeemed" else "expires ${invite.expiresAt}")
            }
            Text(
                text = subtitle,
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
            )
        }
        if (!invite.isRedeemed) {
            IconButton(onClick = onRevoke) {
                Icon(
                    Lucide.Trash2,
                    contentDescription = "Revoke invite",
                    tint = MaterialTheme.colorScheme.error,
                )
            }
        }
    }
}

@Composable
private fun GenerateInviteDialog(onDismiss: () -> Unit, onConfirm: (String?) -> Unit) {
    var note by remember { mutableStateOf("") }
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Generate invite") },
        text = {
            Column {
                Text(
                    text = "Token expires in 24 hours.",
                    style = MaterialTheme.typography.bodyMedium,
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                )
                OutlinedTextField(
                    value = note,
                    onValueChange = { note = it },
                    label = { Text("Note (optional)") },
                    modifier = Modifier.fillMaxWidth().padding(top = 12.dp),
                    singleLine = true,
                )
            }
        },
        confirmButton = {
            Button(onClick = { onConfirm(note.takeIf { it.isNotBlank() }) }) {
                Text("Generate")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) { Text("Cancel") }
        },
    )
}

@Composable
private fun GeneratedInviteDialog(invite: Invite, onDismiss: () -> Unit) {
    val clipboard = LocalClipboard.current
    val scope = rememberCoroutineScope()
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Invite created") },
        text = {
            Column {
                Text(
                    text = "Share this token. It expires in 24 hours.",
                    style = MaterialTheme.typography.bodyMedium,
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                )
                OutlinedTextField(
                    value = invite.token,
                    onValueChange = {},
                    readOnly = true,
                    modifier = Modifier.fillMaxWidth().padding(top = 12.dp),
                )
            }
        },
        confirmButton = {
            Button(
                onClick = {
                    val clip = ClipData.newPlainText("Minstrel invite", invite.token)
                    scope.launch { clipboard.setClipEntry(ClipEntry(clip)) }
                    onDismiss()
                },
            ) {
                Icon(
                    Lucide.Copy,
                    contentDescription = null,
                    modifier = Modifier.size(16.dp),
                )
                Text(" Copy", modifier = Modifier.padding(start = 4.dp))
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) { Text("Close") }
        },
    )
}

@Composable
private fun PendingDialogs(
    resetPasswordFor: AdminUserRef?,
    deleteCandidate: AdminUserRef?,
    onClearReset: () -> Unit,
    onClearDelete: () -> Unit,
    onConfirmReset: (String, String) -> Unit,
    onConfirmDelete: (String) -> Unit,
) {
    resetPasswordFor?.let { user ->
        ResetPasswordDialog(
            user = user,
            onDismiss = onClearReset,
            onConfirm = { newPassword ->
                onConfirmReset(user.id, newPassword)
                onClearReset()
            },
        )
    }
    deleteCandidate?.let { user ->
        DeleteConfirmDialog(
            user = user,
            onDismiss = onClearDelete,
            onConfirm = {
                onConfirmDelete(user.id)
                onClearDelete()
            },
        )
    }
}

@Composable
private fun UserRow(
    user: AdminUserRef,
    onSetAdmin: (Boolean) -> Unit,
    onSetAutoApprove: (Boolean) -> Unit,
    onResetPassword: () -> Unit,
    onDelete: () -> Unit,
) {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 12.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp),
    ) {
        Text(
            text = user.displayName?.takeIf { it.isNotEmpty() } ?: user.username,
            style = MaterialTheme.typography.bodyLarge,
            color = MaterialTheme.colorScheme.onSurface,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis,
        )
        Text(
            text = "@${user.username}",
            style = MaterialTheme.typography.bodySmall,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
        )
        ToggleRow(label = "Admin", checked = user.isAdmin, onChange = onSetAdmin)
        ToggleRow(
            label = "Auto-approve requests",
            checked = user.autoApproveRequests,
            onChange = onSetAutoApprove,
        )
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.End),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            TextButton(onClick = onResetPassword) {
                Icon(
                    Lucide.KeyRound,
                    contentDescription = null,
                    modifier = Modifier.padding(end = 4.dp),
                )
                Text("Reset password")
            }
            TextButton(onClick = onDelete) {
                Icon(
                    Lucide.Trash2,
                    contentDescription = null,
                    tint = MaterialTheme.colorScheme.error,
                    modifier = Modifier.padding(end = 4.dp),
                )
                Text("Delete", color = MaterialTheme.colorScheme.error)
            }
        }
    }
}

@Composable
private fun ToggleRow(label: String, checked: Boolean, onChange: (Boolean) -> Unit) {
    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.SpaceBetween,
    ) {
        Text(text = label, style = MaterialTheme.typography.bodyMedium)
        Switch(checked = checked, onCheckedChange = onChange)
    }
}

@Composable
private fun ResetPasswordDialog(
    user: AdminUserRef,
    onDismiss: () -> Unit,
    onConfirm: (String) -> Unit,
) {
    var newPassword by remember { mutableStateOf("") }
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Reset password") },
        text = {
            Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                Text("Set a new password for @${user.username}.")
                OutlinedTextField(
                    value = newPassword,
                    onValueChange = { newPassword = it },
                    label = { Text("New password") },
                    singleLine = true,
                    visualTransformation = PasswordVisualTransformation(),
                )
            }
        },
        confirmButton = {
            TextButton(
                onClick = { onConfirm(newPassword) },
                enabled = newPassword.isNotEmpty(),
            ) { Text("Reset") }
        },
        dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } },
    )
}

@Composable
private fun DeleteConfirmDialog(
    user: AdminUserRef,
    onDismiss: () -> Unit,
    onConfirm: () -> Unit,
) {
    var typed by remember { mutableStateOf("") }
    val confirmed = typed.trim().equals(DELETE_CONFIRM_WORD, ignoreCase = true)
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Delete user?") },
        text = {
            Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                Text(
                    "Delete @${user.username}? This removes the account and all " +
                        "their data. Type $DELETE_CONFIRM_WORD to confirm.",
                )
                OutlinedTextField(
                    value = typed,
                    onValueChange = { typed = it },
                    label = { Text("Type $DELETE_CONFIRM_WORD") },
                    singleLine = true,
                    modifier = Modifier.fillMaxWidth(),
                )
            }
        },
        confirmButton = {
            TextButton(onClick = onConfirm, enabled = confirmed) {
                Text(
                    "Delete",
                    color = if (confirmed) {
                        MaterialTheme.colorScheme.error
                    } else {
                        MaterialTheme.colorScheme.onSurfaceVariant
                    },
                )
            }
        },
        dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } },
    )
}

private const val DELETE_CONFIRM_WORD = "DELETE"

