package com.anypreta.bountyboard.ui.admin

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.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowDropDown
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import com.anypreta.bountyboard.data.AppContainer
import com.anypreta.bountyboard.data.model.Customer
import com.anypreta.bountyboard.data.model.User
import com.anypreta.bountyboard.data.net.CustomerBody
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.FilterPill
import com.anypreta.bountyboard.ui.components.Hairline
import com.anypreta.bountyboard.ui.components.MessageBox
import com.anypreta.bountyboard.ui.components.MessageKind
import com.anypreta.bountyboard.ui.components.ScreenColumn
import com.anypreta.bountyboard.ui.components.ScreenState
import com.anypreta.bountyboard.ui.components.SectionLabel
import com.anypreta.bountyboard.ui.theme.BB
import kotlinx.coroutines.launch

private val TICKETING_TYPES = listOf("demo", "jira", "azure_devops", "youtrack", "wekan")

/** Credential field keys per ticketing type. */
private fun credentialFields(type: String): List<Pair<String, Boolean>> = when (type) {
    "jira" -> listOf("email" to false, "apiToken" to true)
    "azure_devops" -> listOf("organization" to false, "project" to false, "pat" to true)
    "youtrack" -> listOf("permanentToken" to true)
    "wekan" -> listOf("username" to false, "password" to true)
    else -> emptyList()
}

class CustomerEditViewModel(
    private val container: AppContainer,
    private val customerId: String,
) : ViewModel() {

    val isNew = customerId == "new"

    var loading by mutableStateOf(!isNew)
        private set
    var error by mutableStateOf<String?>(null)
        private set
    var consultants by mutableStateOf<List<User>>(emptyList())
        private set
    var existing by mutableStateOf<Customer?>(null)
        private set

    var saving by mutableStateOf(false)
        private set
    var actionError by mutableStateOf<String?>(null)
        private set
    var testing by mutableStateOf(false)
        private set
    var testMessage by mutableStateOf<String?>(null)
        private set
    var testOk by mutableStateOf(false)
        private set

    init {
        load()
    }

    fun load() {
        loading = !isNew; error = null
        viewModelScope.launch {
            try {
                val cons = container.repo.call { adminUsers(role = "consultant") }
                consultants = cons.users
                if (!isNew) {
                    existing = container.repo.call { adminCustomer(customerId) }.customer
                }
            } catch (e: Exception) {
                error = e.message
            } finally {
                loading = false
            }
        }
    }

    fun testConnection(body: CustomerBody) {
        testing = true; testMessage = null
        viewModelScope.launch {
            try {
                val r = if (isNew) {
                    container.repo.call { adminTestConnectionNew(body) }
                } else {
                    container.repo.call { adminTestConnection(customerId) }
                }
                testOk = r.ok
                testMessage = if (r.ok) "Connected in ${r.latencyMs}ms" else (r.error ?: "Connection failed")
            } catch (e: Exception) {
                testOk = false
                testMessage = e.message
            } finally {
                testing = false
            }
        }
    }

    fun save(body: CustomerBody, onDone: () -> Unit) {
        saving = true; actionError = null
        viewModelScope.launch {
            try {
                if (isNew) {
                    container.repo.call { adminCreateCustomer(body) }
                } else {
                    container.repo.call { adminPatchCustomer(customerId, body) }
                }
                onDone()
            } catch (e: Exception) {
                actionError = e.message
            } finally {
                saving = false
            }
        }
    }
}

@Composable
fun CustomerEditScreen(customerId: String, onDone: () -> Unit) {
    val container = LocalAppContainer.current
    val vm: CustomerEditViewModel = viewModel(
        key = "customer_$customerId",
        factory = containerVMFactory(container) { CustomerEditViewModel(it, customerId) },
    )

    ScreenState(loading = vm.loading, error = vm.error, onRetry = { vm.load() }) {
        CustomerEditForm(vm = vm, onDone = onDone)
    }
}

@Composable
private fun CustomerEditForm(vm: CustomerEditViewModel, onDone: () -> Unit) {
    val p = BB.colors
    val c = vm.existing

    var name by remember { mutableStateOf(c?.name ?: "") }
    var type by remember { mutableStateOf(c?.ticketing?.type ?: "demo") }
    var baseUrl by remember { mutableStateOf(c?.ticketing?.baseUrl ?: "") }
    var projectKey by remember { mutableStateOf(c?.ticketing?.projectKey ?: "") }
    var pollInterval by remember { mutableStateOf((c?.ticketing?.pollIntervalSec ?: 60).toString()) }
    var defaultBudget by remember {
        mutableStateOf(c?.defaultBudget?.takeIf { it > 0.0 }?.let { it.toString() } ?: "")
    }
    val selectedConsultants = remember {
        mutableStateMapOf<String, Boolean>().apply {
            c?.consultantIds?.forEach { put(it, true) }
        }
    }
    val credentials: SnapshotStateMap<String, String> = remember { mutableStateMapOf() }
    var typeMenu by remember { mutableStateOf(false) }

    fun buildBody(): CustomerBody {
        val credMap = credentialFields(type)
            .mapNotNull { (k, _) -> credentials[k]?.takeIf { it.isNotBlank() }?.let { k to it } }
            .toMap()
        return CustomerBody(
            name = name.trim().ifBlank { null },
            type = type,
            baseUrl = baseUrl.trim().ifBlank { null },
            projectKey = projectKey.trim().ifBlank { null },
            pollIntervalSec = pollInterval.toIntOrNull(),
            defaultBudget = defaultBudget.toDoubleOrNull(),
            consultantIds = selectedConsultants.filterValues { it }.keys.toList(),
            credentials = credMap.ifEmpty { null },
            archived = c?.archived,
            version = if (vm.isNew) null else c?.version,
        )
    }

    ScreenColumn {
        Text(
            if (vm.isNew) "New project" else "Edit project",
            style = MaterialTheme.typography.headlineMedium,
            color = p.text,
        )

        BBTextField(value = name, onValueChange = { name = it }, label = "Name", modifier = Modifier.fillMaxWidth())

        // Type selector
        Column {
            SectionLabel("Ticketing type", modifier = Modifier.padding(bottom = 6.dp))
            Box {
                FilterPill(
                    text = type,
                    icon = Icons.Outlined.ArrowDropDown,
                    showCaret = false,
                    onClick = { typeMenu = true },
                )
                DropdownMenu(expanded = typeMenu, onDismissRequest = { typeMenu = false }) {
                    TICKETING_TYPES.forEach { t ->
                        DropdownMenuItem(text = { Text(t) }, onClick = { type = t; typeMenu = false })
                    }
                }
            }
        }

        BBTextField(value = baseUrl, onValueChange = { baseUrl = it }, label = "Base URL", placeholder = "https://…", modifier = Modifier.fillMaxWidth())
        BBTextField(value = projectKey, onValueChange = { projectKey = it }, label = "Project key", modifier = Modifier.fillMaxWidth())
        BBTextField(
            value = pollInterval,
            onValueChange = { pollInterval = it.filter { ch -> ch.isDigit() } },
            label = "Poll interval (sec)",
            keyboardType = KeyboardType.Number,
            modifier = Modifier.fillMaxWidth(),
        )
        BBTextField(
            value = defaultBudget,
            onValueChange = { defaultBudget = it.filter { ch -> ch.isDigit() || ch == '.' } },
            label = "Default budget",
            keyboardType = KeyboardType.Decimal,
            modifier = Modifier.fillMaxWidth(),
        )

        // Consultants
        BBCard(modifier = Modifier.fillMaxWidth()) {
            Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                SectionLabel("Consultants")
                if (vm.consultants.isEmpty()) {
                    Text("No consultants available.", style = MaterialTheme.typography.bodyMedium, color = p.muted)
                } else {
                    vm.consultants.forEach { u ->
                        val checked = selectedConsultants[u.id] == true
                        Row(
                            Modifier.fillMaxWidth(),
                            verticalAlignment = Alignment.CenterVertically,
                            horizontalArrangement = Arrangement.spacedBy(8.dp),
                        ) {
                            Checkbox(
                                checked = checked,
                                onCheckedChange = { selectedConsultants[u.id] = it },
                                colors = CheckboxDefaults.colors(
                                    checkedColor = p.accent,
                                    uncheckedColor = p.border,
                                    checkmarkColor = p.onAccent,
                                ),
                            )
                            Text(u.name.ifBlank { u.email }, style = MaterialTheme.typography.bodyLarge, color = p.text)
                        }
                    }
                }
            }
        }

        // Credentials
        val credFields = credentialFields(type)
        BBCard(modifier = Modifier.fillMaxWidth()) {
            Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
                SectionLabel("Credentials")
                if (credFields.isEmpty()) {
                    Text("Demo needs no credentials.", style = MaterialTheme.typography.bodyMedium, color = p.muted)
                } else {
                    if (!vm.isNew && vm.existing?.ticketing?.hasCredentials == true) {
                        Text("Credentials on file. Leave blank to keep unchanged.", style = MaterialTheme.typography.bodySmall, color = p.muted)
                    }
                    credFields.forEach { (key, secret) ->
                        BBTextField(
                            value = credentials[key] ?: "",
                            onValueChange = { credentials[key] = it },
                            label = key.replaceFirstChar { it.uppercase() },
                            isPassword = secret,
                            modifier = Modifier.fillMaxWidth(),
                        )
                    }
                }
            }
        }

        vm.testMessage?.let {
            MessageBox(it, if (vm.testOk) MessageKind.Ok else MessageKind.Error)
        }
        vm.actionError?.let { MessageBox(it, MessageKind.Error) }

        Hairline()

        Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
            BBButton(
                "Test connection",
                onClick = { vm.testConnection(buildBody()) },
                style = BBButtonStyle.Default,
                loading = vm.testing,
                small = true,
            )
            BBButton(
                "Save",
                onClick = { vm.save(buildBody(), onDone) },
                style = BBButtonStyle.Primary,
                loading = vm.saving,
                small = true,
            )
        }
    }
}
