package com.anypreta.bountyboard.ui.task

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
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.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AttachFile
import androidx.compose.material.icons.outlined.Link
import androidx.compose.material.icons.outlined.OpenInNew
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
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.platform.LocalUriHandler
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.anypreta.bountyboard.data.model.Task
import com.anypreta.bountyboard.di.LocalAppContainer
import com.anypreta.bountyboard.di.containerVMFactory
import com.anypreta.bountyboard.ui.components.BBAvatar
import com.anypreta.bountyboard.ui.components.BBBadge
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.BountyChip
import com.anypreta.bountyboard.ui.components.ConfirmDialog
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.NoteDialog
import com.anypreta.bountyboard.ui.components.RichText
import com.anypreta.bountyboard.ui.components.ScreenState
import com.anypreta.bountyboard.ui.components.SectionLabel
import com.anypreta.bountyboard.ui.components.StatusBadge
import com.anypreta.bountyboard.ui.theme.BB
import com.anypreta.bountyboard.ui.util.formatBounty
import com.anypreta.bountyboard.ui.util.formatMinutes
import com.anypreta.bountyboard.ui.util.htmlToPlain
import com.anypreta.bountyboard.ui.util.relativeTime
import com.anypreta.bountyboard.ui.util.statusLabel

private enum class TaskDialog { Claim, Withdraw, Abandon, Comment, Time, Subdivide, Extend, AssignAi, Review, Edit, Unassign, Archive }

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun TaskDetailScreen(taskId: String, onBack: () -> Unit, onOpenProfile: (String) -> Unit) {
    val container = LocalAppContainer.current
    val vm: TaskDetailViewModel = viewModel(
        key = "task_$taskId",
        factory = containerVMFactory(container) { TaskDetailViewModel(it, taskId) },
    )
    val me by container.session.user.collectAsStateWithLifecycle()
    val p = BB.colors
    val uriHandler = LocalUriHandler.current
    var dialog by remember { mutableStateOf<TaskDialog?>(null) }

    ScreenState(loading = vm.loading, error = vm.error, onRetry = { vm.load() }) {
        val task = vm.task ?: return@ScreenState
        val myId = me?.id
        val roles = me?.roles
        val isCons = roles?.consultant == true || roles?.admin == true
        val isDev = roles?.developer == true
        val isAssignee = task.assignee?.kind == "human" && task.assignee?.userId == myId
        val claimedByMe = task.claimRequests?.any { it.developerId == myId } == true

        Column(
            Modifier
                .fillMaxWidth()
                .verticalScroll(rememberScrollState())
                .padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(14.dp),
        ) {
            // Header
            BBCard(modifier = Modifier.fillMaxWidth(), topStrip = true) {
                Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
                    Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                        BountyChip(task.bounty, large = true)
                        StatusBadge(task.status)
                    }
                    Text(task.title, style = MaterialTheme.typography.headlineMedium, color = p.text)
                    task.external?.let { ext ->
                        if (!ext.key.isNullOrBlank()) {
                            Row(
                                verticalAlignment = Alignment.CenterVertically,
                                horizontalArrangement = Arrangement.spacedBy(4.dp),
                                modifier = Modifier.clickable(enabled = !ext.url.isNullOrBlank()) { ext.url?.let { uriHandler.openUri(it) } },
                            ) {
                                Icon(Icons.Outlined.Link, null, tint = p.muted, modifier = Modifier.size(14.dp))
                                Text("${ext.system ?: ""} ${ext.key}".trim(), style = MaterialTheme.typography.labelSmall, color = p.muted)
                                if (ext.orphaned) BBBadge("Orphaned", color = p.err)
                            }
                        }
                    }
                    Hairline()
                    Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(20.dp)) {
                        MetaStat("Budget", "◈ ${formatBounty(task.budget)}")
                        MetaStat("Coefficient", formatBounty(task.effortCoefficient))
                        MetaStat("Origin", task.origin.replaceFirstChar { it.uppercase() })
                    }
                    task.assignee?.let { a ->
                        Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                            SectionLabel("Assignee")
                            if (a.kind == "ai") {
                                BBBadge("AI performer", color = p.accent)
                            } else {
                                Text(vm.nameFor(a.userId), style = MaterialTheme.typography.bodyMedium, color = p.text)
                            }
                        }
                    }
                }
            }

            // Action messages
            vm.actionError?.let { MessageBox(it, MessageKind.Error) }
            vm.actionInfo?.let { MessageBox(it, MessageKind.Ok) }

            // Actions
            val actions = buildList {
                if (isDev) {
                    if (task.status == "published" && !claimedByMe) add("Request assignment" to { dialog = TaskDialog.Claim })
                    if ((task.status == "published" || task.status == "claim_requested") && claimedByMe) add("Withdraw claim" to { dialog = TaskDialog.Withdraw })
                    if (isAssignee && task.status == "assigned") add("Start work" to { vm.start() })
                    if (isAssignee && task.status == "changes_requested") add("Resume work" to { vm.start() })
                    if (isAssignee && task.status == "in_progress") {
                        add("Submit for review" to { vm.submitReview() })
                        add("Abandon" to { dialog = TaskDialog.Abandon })
                    }
                    if (isAssignee && task.status in listOf("assigned", "in_progress", "changes_requested")) {
                        add("Log time" to { dialog = TaskDialog.Time })
                    }
                }
                if (isCons) {
                    if (task.status in listOf("imported", "atomized")) {
                        add("Subdivide" to { dialog = TaskDialog.Subdivide })
                        add("Extend" to { dialog = TaskDialog.Extend })
                    }
                    if (task.status == "atomized") add("Publish" to { vm.publish() })
                    if (task.status in listOf("published", "claim_requested")) add("Assign to AI" to { dialog = TaskDialog.AssignAi })
                    if (task.status in listOf("assigned", "in_progress", "changes_requested")) add("Unassign" to { dialog = TaskDialog.Unassign })
                    if (task.status == "in_review") add("Review" to { dialog = TaskDialog.Review })
                    if (task.status !in listOf("approved", "archived")) add("Edit" to { dialog = TaskDialog.Edit })
                    if (task.status != "archived") add("Archive" to { dialog = TaskDialog.Archive })
                }
                add("Comment" to { dialog = TaskDialog.Comment })
            }
            if (actions.isNotEmpty()) {
                FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
                    actions.forEachIndexed { i, (label, onClick) ->
                        BBButton(
                            label,
                            onClick = onClick,
                            style = if (i == 0) BBButtonStyle.Primary else BBButtonStyle.Default,
                            small = true,
                            loading = vm.actionLoading && i == 0,
                        )
                    }
                }
            }

            // Description
            if (task.description.isNotBlank()) {
                SectionCard("Description") {
                    RichText(task.description, style = MaterialTheme.typography.bodyLarge, color = p.text)
                }
            }

            // Acceptance criteria
            task.acceptanceCriteria?.takeIf { it.isNotEmpty() }?.let { acs ->
                SectionCard("Acceptance criteria") {
                    Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
                        acs.forEach { c ->
                            Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                                Text("◆", color = p.accent, style = MaterialTheme.typography.bodyMedium)
                                Text(c, style = MaterialTheme.typography.bodyMedium, color = p.text)
                            }
                        }
                    }
                }
            }

            // Attachments & links
            val hasAttach = !task.attachments.isNullOrEmpty()
            val hasLinks = !task.links.isNullOrEmpty()
            if (hasAttach || hasLinks) {
                SectionCard("Attachments & links") {
                    Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                        task.attachments?.forEach { a ->
                            LinkRow(Icons.Outlined.AttachFile, a.name ?: "Attachment") {
                                val url = a.url ?: a.fileId?.let { container.fileUrl(it) }
                                url?.let { uriHandler.openUri(it) }
                            }
                        }
                        task.links?.forEach { l ->
                            LinkRow(Icons.Outlined.Link, l) { uriHandler.openUri(l) }
                        }
                    }
                }
            }

            // Claim requests
            task.claimRequests?.takeIf { it.isNotEmpty() }?.let { claims ->
                SectionCard("Claim requests (${claims.size})") {
                    Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
                        claims.forEach { c ->
                            Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
                                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                                    Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.clickable { onOpenProfile(c.developerId) }) {
                                        BBAvatar(vm.nameFor(c.developerId), null, size = 28.dp)
                                        Column {
                                            Text(vm.nameFor(c.developerId), style = MaterialTheme.typography.bodyMedium, color = p.text, fontWeight = FontWeight.Bold)
                                            Text(relativeTime(c.at), style = MaterialTheme.typography.labelSmall, color = p.muted)
                                        }
                                    }
                                    if (c.developerId == myId) BBBadge("You", color = p.ok)
                                }
                                if (!c.note.isNullOrBlank()) {
                                    Text(c.note!!, style = MaterialTheme.typography.bodyMedium, color = p.muted)
                                }
                                if (isCons && task.status in listOf("published", "claim_requested")) {
                                    Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                                        BBButton("Approve", onClick = { vm.approveClaim(c.developerId) }, style = BBButtonStyle.Primary, small = true)
                                        BBButton("Decline", onClick = { vm.declineClaim(c.developerId) }, style = BBButtonStyle.Ghost, small = true)
                                    }
                                }
                                Hairline()
                            }
                        }
                    }
                }
            }

            // Comments
            SectionCard("Comments (${task.comments?.size ?: 0})") {
                Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                    if (task.comments.isNullOrEmpty()) {
                        Text("No comments yet.", style = MaterialTheme.typography.bodyMedium, color = p.muted)
                    } else {
                        task.comments!!.forEach { c ->
                            Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                                BBAvatar(vm.nameFor(c.authorId), null, size = 28.dp)
                                Column {
                                    Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp)) {
                                        Text(vm.nameFor(c.authorId), style = MaterialTheme.typography.titleSmall, color = p.text)
                                        Text(relativeTime(c.at), style = MaterialTheme.typography.labelSmall, color = p.muted)
                                    }
                                    RichText(c.body, style = MaterialTheme.typography.bodyMedium, color = p.text)
                                }
                            }
                        }
                    }
                    BBButton("Add comment", onClick = { dialog = TaskDialog.Comment }, style = BBButtonStyle.Default, small = true)
                }
            }

            // Time log
            task.timeLog?.takeIf { it.isNotEmpty() }?.let { logs ->
                SectionCard("Time log") {
                    Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
                        val total = logs.sumOf { it.minutes }
                        Text("Total: ${formatMinutes(total)}", style = MaterialTheme.typography.titleSmall, color = p.accent)
                        logs.forEach { e ->
                            Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                                Text(e.note?.ifBlank { "—" } ?: "—", style = MaterialTheme.typography.bodyMedium, color = p.text)
                                Text(formatMinutes(e.minutes), style = MaterialTheme.typography.bodyMedium, color = p.muted)
                            }
                        }
                    }
                }
            }

            // Timeline
            task.timeline?.takeIf { it.isNotEmpty() }?.let { tl ->
                SectionCard("Timeline") {
                    Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                        tl.reversed().take(30).forEach { e ->
                            Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                                Text("•", color = p.accent)
                                Column {
                                    Text(statusLabel(e.event ?: ""), style = MaterialTheme.typography.bodyMedium, color = p.text)
                                    Text(relativeTime(e.at), style = MaterialTheme.typography.labelSmall, color = p.muted)
                                }
                            }
                        }
                    }
                }
            }

            Spacer(Modifier.height(40.dp))
        }

        // Dialogs
        when (dialog) {
            TaskDialog.Claim -> NoteDialog("Request assignment", "Pitch note (optional)", "Request", onConfirm = { vm.claim(it.ifBlank { null }); dialog = null }, onDismiss = { dialog = null }, message = "Optionally add a pitch.")
            TaskDialog.Withdraw -> ConfirmDialog("Withdraw claim", "Remove your assignment request from this task?", "Withdraw", onConfirm = { vm.withdrawClaim(); dialog = null }, onDismiss = { dialog = null })
            TaskDialog.Abandon -> ConfirmDialog("Abandon task", "Return this task to the board? Your progress note stays in the timeline.", "Abandon", danger = true, onConfirm = { vm.abandon(); dialog = null }, onDismiss = { dialog = null })
            TaskDialog.Comment -> NoteDialog("Add comment", "Comment", "Post", required = true, onConfirm = { vm.comment(it); dialog = null }, onDismiss = { dialog = null }, message = "Mention teammates with @name.")
            TaskDialog.Time -> TimeDialog(onConfirm = { m, n -> vm.logTime(m, n); dialog = null }, onDismiss = { dialog = null })
            TaskDialog.Subdivide -> SubdivideDialog(onConfirm = { note, min, max -> vm.subdivide(note, min, max); dialog = null }, onDismiss = { dialog = null })
            TaskDialog.Extend -> NoteDialog("Extend task", "Extension note", "Extend", required = true, onConfirm = { vm.extend(it); dialog = null }, onDismiss = { dialog = null }, message = "Describe the parallel task to create.")
            TaskDialog.AssignAi -> AssignAiDialog(onConfirm = { r, b, i -> vm.assignAi(r, b, i); dialog = null }, onDismiss = { dialog = null })
            TaskDialog.Review -> ReviewDialog(task, onConfirm = { a, n, cl -> vm.review(a, n, cl); dialog = null }, onDismiss = { dialog = null })
            TaskDialog.Edit -> EditTaskDialog(task, onConfirm = { t, d, ac, c, b -> vm.patch(t, d, ac, c, b) { dialog = null } }, onDismiss = { dialog = null })
            TaskDialog.Unassign -> ConfirmDialog("Unassign task", "Return this task to the board?", "Unassign", danger = true, onConfirm = { vm.unassign(); dialog = null }, onDismiss = { dialog = null })
            TaskDialog.Archive -> ConfirmDialog("Archive task", "Archive this task? It will leave all active boards.", "Archive", danger = true, onConfirm = { vm.archive(); dialog = null }, onDismiss = { dialog = null })
            null -> {}
        }
    }
}

@Composable
private fun MetaStat(label: String, value: String) {
    val p = BB.colors
    Column {
        SectionLabel(label)
        Text(value, style = MaterialTheme.typography.titleMedium, color = p.text)
    }
}

@Composable
private fun SectionCard(title: String, content: @Composable () -> Unit) {
    BBCard(modifier = Modifier.fillMaxWidth()) {
        Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
            SectionLabel(title)
            content()
        }
    }
}

@Composable
private fun LinkRow(icon: androidx.compose.ui.graphics.vector.ImageVector, label: String, onClick: () -> Unit) {
    val p = BB.colors
    Row(
        Modifier.fillMaxWidth().clickable(onClick = onClick),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(8.dp),
    ) {
        Icon(icon, null, tint = p.accent, modifier = Modifier.size(16.dp))
        Text(label, style = MaterialTheme.typography.bodyMedium, color = p.accent, modifier = Modifier.weight(1f), maxLines = 1)
        Icon(Icons.Outlined.OpenInNew, null, tint = p.muted, modifier = Modifier.size(14.dp))
    }
}
