package com.anypreta.bountyboard.ui.auth

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
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.layout.widthIn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Dns
import androidx.compose.material.icons.outlined.ExpandLess
import androidx.compose.material.icons.outlined.ExpandMore
import androidx.compose.material.icons.outlined.Key
import androidx.compose.material.icons.outlined.Lock
import androidx.compose.material.icons.outlined.Mail
import androidx.compose.material.icons.outlined.Person
import androidx.compose.material3.Icon
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.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.anypreta.bountyboard.di.LocalAppContainer
import com.anypreta.bountyboard.di.containerVMFactory
import com.anypreta.bountyboard.ui.components.BBButton
import com.anypreta.bountyboard.ui.components.BBButtonStyle
import com.anypreta.bountyboard.ui.components.BBCard
import com.anypreta.bountyboard.ui.components.BBTextField
import com.anypreta.bountyboard.ui.components.Kicker
import com.anypreta.bountyboard.ui.components.MessageBox
import com.anypreta.bountyboard.ui.components.MessageKind
import com.anypreta.bountyboard.ui.theme.BB
import com.anypreta.bountyboard.ui.theme.Fraunces
import androidx.compose.ui.text.input.KeyboardType

@Composable
fun AuthFlow() {
    val nav = rememberNavController()
    NavHost(nav, startDestination = "login") {
        composable("login") {
            LoginScreen(
                onRegister = { nav.navigate("register") },
                onForgot = { nav.navigate("forgot") },
                onOidc = { nav.navigate("oidc") },
            )
        }
        composable("register") { RegisterScreen(onBack = { nav.popBackStack() }) }
        composable("forgot") { ForgotScreen(onBack = { nav.popBackStack() }) }
        composable("oidc") {
            OidcWebViewScreen(onDone = { nav.popBackStack() })
        }
    }
}

@Composable
private fun AuthScaffold(content: @Composable () -> Unit) {
    val p = BB.colors
    Box(
        Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
            .padding(horizontal = 20.dp, vertical = 32.dp),
        contentAlignment = Alignment.TopCenter,
    ) {
        Column(
            Modifier.widthIn(max = 460.dp).fillMaxWidth(),
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {
            content()
        }
    }
}

@Composable
private fun Masthead() {
    val p = BB.colors
    Spacer(Modifier.height(16.dp))
    Kicker("Consulting Work Exchange")
    Spacer(Modifier.height(10.dp))
    Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
        Text("◈", color = p.accent, fontFamily = Fraunces, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.displayMedium)
        Text("Bounty Board", color = p.text, fontFamily = Fraunces, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.displayMedium)
    }
    Spacer(Modifier.height(6.dp))
    Text("❦", color = p.accent, style = MaterialTheme.typography.titleLarge)
    Spacer(Modifier.height(24.dp))
}

@Composable
fun LoginScreen(onRegister: () -> Unit, onForgot: () -> Unit, onOidc: () -> Unit) {
    val container = LocalAppContainer.current
    val vm: AuthViewModel = viewModel(factory = containerVMFactory(container) { AuthViewModel(it) })
    val p = BB.colors

    var email by rememberSaveable { mutableStateOf("") }
    var password by rememberSaveable { mutableStateOf("") }
    var serverExpanded by rememberSaveable { mutableStateOf(false) }
    var baseUrl by rememberSaveable { mutableStateOf(vm.initialBaseUrl) }

    AuthScaffold {
        Masthead()
        BBCard(modifier = Modifier.fillMaxWidth()) {
            Column(verticalArrangement = Arrangement.spacedBy(14.dp)) {
                Text("Sign in", style = MaterialTheme.typography.headlineMedium, color = p.text)

                vm.error?.let { MessageBox(it, MessageKind.Error) }
                vm.info?.let { MessageBox(it, MessageKind.Ok) }

                BBTextField(
                    value = email, onValueChange = { email = it; vm.clearMessages() },
                    label = "Email", placeholder = "you@company.com",
                    keyboardType = KeyboardType.Email, leadingIcon = Icons.Outlined.Mail,
                )
                BBTextField(
                    value = password, onValueChange = { password = it; vm.clearMessages() },
                    label = "Password", isPassword = true, leadingIcon = Icons.Outlined.Lock,
                )
                BBButton(
                    "Sign in", onClick = { vm.applyBaseUrl(baseUrl); vm.login(email, password) },
                    style = BBButtonStyle.Primary, loading = vm.loading,
                    modifier = Modifier.fillMaxWidth(),
                )

                Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                    Box(Modifier.weight(1f).height(1.dp).background(p.border.copy(alpha = 0.6f)))
                    Text("OR", style = MaterialTheme.typography.labelSmall, color = p.muted)
                    Box(Modifier.weight(1f).height(1.dp).background(p.border.copy(alpha = 0.6f)))
                }
                BBButton(
                    "Sign in with SSO",
                    onClick = { vm.applyBaseUrl(baseUrl); onOidc() },
                    style = BBButtonStyle.Default,
                    leadingIcon = Icons.Outlined.Key,
                    modifier = Modifier.fillMaxWidth(),
                )

                Row(
                    Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                ) {
                    TextButton(onClick = onForgot) { Text("Forgot password?", color = p.accent, style = MaterialTheme.typography.bodyMedium) }
                    TextButton(onClick = onRegister) { Text("Create account", color = p.accent, style = MaterialTheme.typography.bodyMedium) }
                }
            }
        }

        Spacer(Modifier.height(16.dp))

        // Server / base URL configuration
        BBCard(modifier = Modifier.fillMaxWidth()) {
            Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                Row(
                    Modifier
                        .fillMaxWidth()
                        .padding(vertical = 2.dp),
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.SpaceBetween,
                ) {
                    Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                        Icon(Icons.Outlined.Dns, null, tint = p.muted, modifier = Modifier.height(18.dp))
                        Column {
                            Text("Server", style = MaterialTheme.typography.titleSmall, color = p.text)
                            Text(baseUrl, style = MaterialTheme.typography.labelSmall, color = p.muted, maxLines = 1)
                        }
                    }
                    TextButton(onClick = { serverExpanded = !serverExpanded }) {
                        Icon(
                            if (serverExpanded) Icons.Outlined.ExpandLess else Icons.Outlined.ExpandMore,
                            "Toggle", tint = p.accent,
                        )
                    }
                }
                AnimatedVisibility(serverExpanded) {
                    Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
                        BBTextField(
                            value = baseUrl, onValueChange = { baseUrl = it },
                            label = "Base URL", placeholder = "https://bountyboard.anypreta.com/",
                            keyboardType = KeyboardType.Uri,
                            supportingText = "The BountyBoard server this app connects to.",
                        )
                        BBButton(
                            "Save server", onClick = { vm.applyBaseUrl(baseUrl) },
                            style = BBButtonStyle.Default, small = true,
                        )
                    }
                }
            }
        }
        Spacer(Modifier.height(32.dp))
    }
}

@Composable
fun RegisterScreen(onBack: () -> Unit) {
    val container = LocalAppContainer.current
    val vm: AuthViewModel = viewModel(factory = containerVMFactory(container) { AuthViewModel(it) })
    val p = BB.colors
    var name by rememberSaveable { mutableStateOf("") }
    var email by rememberSaveable { mutableStateOf("") }
    var password by rememberSaveable { mutableStateOf("") }

    AuthScaffold {
        Masthead()
        BBCard(modifier = Modifier.fillMaxWidth()) {
            Column(verticalArrangement = Arrangement.spacedBy(14.dp)) {
                Text("Create developer account", style = MaterialTheme.typography.headlineMedium, color = p.text)
                Text(
                    "Open registration creates a developer account in the global pool.",
                    style = MaterialTheme.typography.bodyMedium, color = p.muted,
                )
                vm.error?.let { MessageBox(it, MessageKind.Error) }
                BBTextField(name, { name = it; vm.clearMessages() }, "Name", leadingIcon = Icons.Outlined.Person)
                BBTextField(email, { email = it; vm.clearMessages() }, "Email", keyboardType = KeyboardType.Email, leadingIcon = Icons.Outlined.Mail)
                BBTextField(password, { password = it; vm.clearMessages() }, "Password", isPassword = true, leadingIcon = Icons.Outlined.Lock, supportingText = "At least 8 characters.")
                BBButton("Create account", onClick = { vm.register(email, name, password) }, style = BBButtonStyle.Primary, loading = vm.loading, modifier = Modifier.fillMaxWidth())
                TextButton(onClick = onBack, modifier = Modifier.fillMaxWidth()) {
                    Text("Back to sign in", color = p.accent, textAlign = TextAlign.Center)
                }
            }
        }
        Spacer(Modifier.height(32.dp))
    }
}

@Composable
fun ForgotScreen(onBack: () -> Unit) {
    val container = LocalAppContainer.current
    val vm: AuthViewModel = viewModel(factory = containerVMFactory(container) { AuthViewModel(it) })
    val p = BB.colors
    var email by rememberSaveable { mutableStateOf("") }

    AuthScaffold {
        Masthead()
        BBCard(modifier = Modifier.fillMaxWidth()) {
            Column(verticalArrangement = Arrangement.spacedBy(14.dp)) {
                Text("Reset password", style = MaterialTheme.typography.headlineMedium, color = p.text)
                Text(
                    "Enter your email and we'll send a reset link (if email is configured on the server).",
                    style = MaterialTheme.typography.bodyMedium, color = p.muted,
                )
                vm.error?.let { MessageBox(it, MessageKind.Error) }
                vm.info?.let { MessageBox(it, MessageKind.Ok) }
                BBTextField(email, { email = it; vm.clearMessages() }, "Email", keyboardType = KeyboardType.Email, leadingIcon = Icons.Outlined.Mail)
                BBButton("Send reset link", onClick = { vm.forgot(email) {} }, style = BBButtonStyle.Primary, loading = vm.loading, modifier = Modifier.fillMaxWidth())
                TextButton(onClick = onBack, modifier = Modifier.fillMaxWidth()) {
                    Text("Back to sign in", color = p.accent, textAlign = TextAlign.Center)
                }
            }
        }
        Spacer(Modifier.height(32.dp))
    }
}

@Composable
fun ForcedChangePasswordScreen() {
    val container = LocalAppContainer.current
    val vm: AuthViewModel = viewModel(factory = containerVMFactory(container) { AuthViewModel(it) })
    val p = BB.colors
    var current by rememberSaveable { mutableStateOf("") }
    var next by rememberSaveable { mutableStateOf("") }
    var confirm by rememberSaveable { mutableStateOf("") }

    AuthScaffold {
        Masthead()
        BBCard(modifier = Modifier.fillMaxWidth()) {
            Column(verticalArrangement = Arrangement.spacedBy(14.dp)) {
                Text("Change your password", style = MaterialTheme.typography.headlineMedium, color = p.text)
                Text(
                    "Your account requires a new password before continuing.",
                    style = MaterialTheme.typography.bodyMedium, color = p.muted,
                )
                vm.error?.let { MessageBox(it, MessageKind.Error) }
                BBTextField(current, { current = it; vm.clearMessages() }, "Current password", isPassword = true, leadingIcon = Icons.Outlined.Lock)
                BBTextField(next, { next = it; vm.clearMessages() }, "New password", isPassword = true, leadingIcon = Icons.Outlined.Lock, supportingText = "At least 8 characters.")
                BBTextField(
                    confirm, { confirm = it; vm.clearMessages() }, "Confirm new password", isPassword = true,
                    leadingIcon = Icons.Outlined.Lock,
                    isError = confirm.isNotEmpty() && confirm != next,
                )
                BBButton(
                    "Update password",
                    onClick = { vm.changePassword(current, next) {} },
                    enabled = next.isNotEmpty() && next == confirm,
                    style = BBButtonStyle.Primary, loading = vm.loading, modifier = Modifier.fillMaxWidth(),
                )
                TextButton(
                    onClick = { container.session.clear(); container.cookieJar.clear() },
                    modifier = Modifier.fillMaxWidth(),
                ) {
                    Text("Sign out", color = p.muted, textAlign = TextAlign.Center)
                }
            }
        }
        Spacer(Modifier.height(32.dp))
    }
}
