package wang.yaojia.webterm.screens

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.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
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.AssistChip
import androidx.compose.material3.AssistChipDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
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.platform.LocalUriHandler
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.launch
import wang.yaojia.webterm.api.models.CommitLogEntry
import wang.yaojia.webterm.api.models.PrAvailability
import wang.yaojia.webterm.api.models.PrStatus
import wang.yaojia.webterm.api.models.ProjectDetail
import wang.yaojia.webterm.api.models.ProjectSessionRef
import wang.yaojia.webterm.api.models.WorktreeInfo
import wang.yaojia.webterm.designsystem.Spacing
import wang.yaojia.webterm.designsystem.Stroke
import wang.yaojia.webterm.designsystem.WebTermCard
import wang.yaojia.webterm.designsystem.WebTermColors
import wang.yaojia.webterm.designsystem.WebTermTheme
import wang.yaojia.webterm.designsystem.WebTermType
import wang.yaojia.webterm.viewmodels.ProjectDetailViewModel
import wang.yaojia.webterm.viewmodels.WorktreeViewModel
import java.net.URI

/**
 * # ProjectDetailScreen (A23 + W5) — one project's detail (branch · worktrees · sessions · CLAUDE.md),
 * plus the W5 additions: a **PR + CI chip** (tappable only when the PR url parses as https), a
 * **recent-commits** section, and guarded **worktree create / remove / prune** actions.
 *
 * Every server string (name/path/branch/worktree/CLAUDE.md/commit subject/PR title/error) is rendered
 * as **inert [Text]** — no autolink/markdown (plan §8). The single exception is the PR chip, which is a
 * link ONLY when its url is a valid https URL (scheme-validated before it is made clickable). The
 * worktree actions drive [ProjectDetailViewModel.worktree]; a remove force-confirms in a dialog and a
 * main worktree is never removable.
 */
@Composable
public fun ProjectDetailScreen(
    viewModel: ProjectDetailViewModel,
    onBack: () -> Unit,
    onOpenClaude: (String) -> Unit,
    modifier: Modifier = Modifier,
    onViewDiff: (String) -> Unit = {},
) {
    val phase by viewModel.phase.collectAsStateWithLifecycle()
    val prChip by viewModel.prChip.collectAsStateWithLifecycle()
    val recent by viewModel.recentCommits.collectAsStateWithLifecycle()
    val scope = rememberCoroutineScope()
    LaunchedEffect(viewModel) { viewModel.load() }

    Surface(modifier = modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
        Column(modifier = Modifier.fillMaxSize()) {
            DetailHeaderBar(onBack = onBack)
            HorizontalDivider(color = MaterialTheme.colorScheme.outline, thickness = Stroke.hairline)
            Box(modifier = Modifier.fillMaxSize()) {
                when (val current = phase) {
                    is ProjectDetailViewModel.Phase.Loading -> Centered { CircularProgressIndicator() }
                    is ProjectDetailViewModel.Phase.Failed ->
                        Failure(current.failure, onRetry = { scope.launch { viewModel.load() } })
                    is ProjectDetailViewModel.Phase.Loaded ->
                        DetailBody(
                            detail = current.detail,
                            prChip = prChip,
                            recent = recent,
                            worktree = viewModel.worktree,
                            onOpenClaude = onOpenClaude,
                            onViewDiff = onViewDiff,
                        )
                }
            }
        }
    }
}

@Composable
private fun DetailHeaderBar(onBack: () -> Unit) {
    Row(
        modifier = Modifier.fillMaxWidth().padding(horizontal = Spacing.md12, vertical = Spacing.sm8),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(Spacing.sm8),
    ) {
        TextButton(onClick = onBack) { Text("← 全部项目") }
    }
}

@Composable
private fun DetailBody(
    detail: ProjectDetail,
    prChip: ProjectDetailViewModel.PrChip,
    recent: ProjectDetailViewModel.RecentCommits,
    worktree: WorktreeViewModel?,
    onOpenClaude: (String) -> Unit,
    onViewDiff: (String) -> Unit = {},
) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
            .padding(Spacing.md12),
        verticalArrangement = Arrangement.spacedBy(Spacing.sm8),
    ) {
        Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(Spacing.sm8)) {
            Text(
                text = detail.name,
                style = MaterialTheme.typography.titleLarge,
                fontWeight = FontWeight.SemiBold,
                color = MaterialTheme.colorScheme.onBackground,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
                modifier = Modifier.weight(1f),
            )
            detail.branch?.let { Text(text = it, style = WebTermType.metaMono, color = MaterialTheme.colorScheme.onSurfaceVariant) }
            if (detail.dirty == true) Text(text = "●", color = WebTermColors.statusWaiting)
        }
        Text(text = detail.path, style = WebTermType.metaMono, color = MaterialTheme.colorScheme.onSurfaceVariant)

        PrChipRow(prChip)

        if (detail.isGit && worktree != null) {
            WorktreeSection(detail = detail, worktree = worktree)
        } else {
            SectionTitle(if (detail.worktrees.size > 1) "工作树" else "分支")
            if (!detail.isGit) EmptyLine("不是 git 仓库。")
            else if (detail.worktrees.isEmpty()) EmptyLine(detail.branch?.let { "当前分支 $it" } ?: "无工作树信息。")
            else for (w in detail.worktrees) WorktreeRow(w, onRemove = null)
        }

        val running = detail.sessions.filter { !it.exited }
        SectionTitle("运行中的会话（${running.size}）")
        if (running.isEmpty()) EmptyLine("没有运行中的会话 —— 在下方开一个。")
        else for (session in running) SessionRow(session)

        RecentCommitsSection(recent)

        SectionTitle("CLAUDE.md")
        val claudeMd = detail.claudeMd
        if (detail.hasClaudeMd && claudeMd != null) ClaudeMdBlock(claudeMd)
        else EmptyLine("还没有 CLAUDE.md —— 生成一个以给 Claude 项目专属指令。")

        Row(horizontalArrangement = Arrangement.spacedBy(Spacing.sm8)) {
            TextButton(onClick = { onOpenClaude(detail.path) }) { Text("在此启动 Claude") }
            if (detail.isGit) TextButton(onClick = { onViewDiff(detail.path) }) { Text("查看改动 (diff)") }
        }
    }
}

// ── PR + CI chip (link only when https) ──────────────────────────────────────────────────────────

@Composable
private fun PrChipRow(prChip: ProjectDetailViewModel.PrChip) {
    when (prChip) {
        ProjectDetailViewModel.PrChip.Hidden -> Unit
        ProjectDetailViewModel.PrChip.Loading -> EmptyLine("正在读取 PR 状态…")
        ProjectDetailViewModel.PrChip.Unavailable -> EmptyLine("PR 状态不可用。")
        is ProjectDetailViewModel.PrChip.Loaded -> PrChipContent(prChip.status)
    }
}

@Composable
private fun PrChipContent(pr: PrStatus) {
    val uriHandler = LocalUriHandler.current
    val httpsUrl = pr.url?.let { if (isHttpsUrl(it)) it else null } // link ONLY when https (plan §Security)
    val label = prChipLabel(pr)
    val color = prChipColor(pr)
    if (httpsUrl != null && pr.availability == PrAvailability.OK) {
        AssistChip(
            onClick = { runCatching { uriHandler.openUri(httpsUrl) } },
            label = { Text(label, maxLines = 1, overflow = TextOverflow.Ellipsis) },
            colors = AssistChipDefaults.assistChipColors(labelColor = color),
        )
    } else {
        // Non-ok / non-https → an INERT, non-clickable line (never make a hostile url tappable).
        Text(text = label, style = WebTermType.metaMono, color = color)
    }
}

private fun prChipLabel(pr: PrStatus): String = when (pr.availability) {
    PrAvailability.OK -> {
        val num = pr.number?.let { "#$it " } ?: ""
        val checks = pr.checks?.let { " (${it.passing}/${it.total})" } ?: ""
        "PR $num${pr.title ?: ""}$checks".trim()
    }
    PrAvailability.NO_PR -> "当前分支没有 PR"
    PrAvailability.NOT_INSTALLED -> "未安装 gh，无法读取 PR"
    PrAvailability.UNAUTHENTICATED -> "gh 未登录，无法读取 PR"
    PrAvailability.DISABLED -> "PR 集成已禁用"
    PrAvailability.ERROR -> "PR 状态读取失败"
}

@Composable
private fun prChipColor(pr: PrStatus): androidx.compose.ui.graphics.Color = when {
    pr.availability != PrAvailability.OK -> MaterialTheme.colorScheme.onSurfaceVariant
    (pr.checks?.failing ?: 0) > 0 -> WebTermColors.statusStuck
    (pr.checks?.pending ?: 0) > 0 -> WebTermColors.statusWaiting
    else -> WebTermColors.statusWorking
}

private fun isHttpsUrl(url: String): Boolean =
    runCatching { URI(url.trim()).scheme?.lowercase() == "https" }.getOrDefault(false)

// ── Worktree section (create / remove / prune) ────────────────────────────────────────────────────

@Composable
private fun WorktreeSection(detail: ProjectDetail, worktree: WorktreeViewModel) {
    val scope = rememberCoroutineScope()
    val phase by worktree.phase.collectAsStateWithLifecycle()
    var branch by remember { mutableStateOf("") }
    var base by remember { mutableStateOf("") }
    var removeTarget by remember { mutableStateOf<WorktreeInfo?>(null) }

    SectionTitle(if (detail.worktrees.size > 1) "工作树" else "分支")
    if (detail.worktrees.isEmpty()) {
        EmptyLine(detail.branch?.let { "当前分支 $it" } ?: "无工作树信息。")
    } else {
        for (w in detail.worktrees) WorktreeRow(w, onRemove = { if (!w.isMain) removeTarget = w })
    }

    // New-worktree inline form.
    WebTermCard(modifier = Modifier.fillMaxWidth()) {
        Column(verticalArrangement = Arrangement.spacedBy(Spacing.xs4)) {
            OutlinedTextField(
                value = branch,
                onValueChange = { branch = it },
                label = { Text("新工作树分支名") },
                singleLine = true,
                modifier = Modifier.fillMaxWidth(),
            )
            OutlinedTextField(
                value = base,
                onValueChange = { base = it },
                label = { Text("基点（可选）") },
                singleLine = true,
                modifier = Modifier.fillMaxWidth(),
            )
            Row(horizontalArrangement = Arrangement.spacedBy(Spacing.sm8)) {
                OutlinedButton(
                    enabled = phase != WorktreeViewModel.Phase.Working,
                    onClick = { scope.launch { worktree.create(branch, base) } },
                ) { Text("新建工作树") }
                OutlinedButton(
                    enabled = phase != WorktreeViewModel.Phase.Working,
                    onClick = { scope.launch { worktree.prune() } },
                ) { Text("清理") }
            }
            WorktreePhaseBanner(phase, onDismiss = { worktree.reset() })
        }
    }

    val target = removeTarget
    if (target != null) {
        RemoveWorktreeDialog(
            worktree = target,
            onConfirm = { force ->
                removeTarget = null
                scope.launch { worktree.remove(target, force) }
            },
            onDismiss = { removeTarget = null },
        )
    }
}

@Composable
private fun WorktreePhaseBanner(phase: WorktreeViewModel.Phase, onDismiss: () -> Unit) {
    when (phase) {
        WorktreeViewModel.Phase.Idle -> Unit
        WorktreeViewModel.Phase.Working -> Text("处理中…", style = WebTermType.metaMono, color = MaterialTheme.colorScheme.onSurfaceVariant)
        is WorktreeViewModel.Phase.Done -> BannerLine(phase.message, WebTermColors.statusWorking, onDismiss)
        is WorktreeViewModel.Phase.Failed -> BannerLine(phase.message, WebTermColors.statusStuck, onDismiss)
    }
}

@Composable
private fun BannerLine(message: String, color: androidx.compose.ui.graphics.Color, onDismiss: () -> Unit) {
    Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(Spacing.sm8)) {
        Text(text = message, style = WebTermType.metaMono, color = color, modifier = Modifier.weight(1f))
        TextButton(onClick = onDismiss) { Text("知道了") }
    }
}

@Composable
private fun RemoveWorktreeDialog(
    worktree: WorktreeInfo,
    onConfirm: (force: Boolean) -> Unit,
    onDismiss: () -> Unit,
) {
    var force by remember { mutableStateOf(false) }
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("删除工作树") },
        text = {
            Column(verticalArrangement = Arrangement.spacedBy(Spacing.xs4)) {
                Text(text = worktree.path, style = WebTermType.metaMono, color = MaterialTheme.colorScheme.onSurface)
                Row(verticalAlignment = Alignment.CenterVertically) {
                    Checkbox(checked = force, onCheckedChange = { force = it })
                    Text("强制删除（丢弃未提交改动）")
                }
            }
        },
        confirmButton = { TextButton(onClick = { onConfirm(force) }) { Text("删除") } },
        dismissButton = { TextButton(onClick = onDismiss) { Text("取消") } },
    )
}

// ── Recent commits ────────────────────────────────────────────────────────────────────────────────

@Composable
private fun RecentCommitsSection(recent: ProjectDetailViewModel.RecentCommits) {
    when (recent) {
        ProjectDetailViewModel.RecentCommits.Hidden -> Unit
        ProjectDetailViewModel.RecentCommits.Loading -> {
            SectionTitle("最近提交"); EmptyLine("正在读取提交记录…")
        }
        ProjectDetailViewModel.RecentCommits.Unavailable -> {
            SectionTitle("最近提交"); EmptyLine("提交记录不可用。")
        }
        is ProjectDetailViewModel.RecentCommits.Loaded -> {
            SectionTitle("最近提交")
            if (recent.result.commits.isEmpty()) EmptyLine("暂无提交。")
            else for (commit in recent.result.commits) CommitRow(commit)
        }
    }
}

@Composable
private fun CommitRow(commit: CommitLogEntry) {
    Row(horizontalArrangement = Arrangement.spacedBy(Spacing.sm8), modifier = Modifier.fillMaxWidth()) {
        Text(
            text = commit.hash.take(7),
            style = WebTermType.metaMono,
            color = MaterialTheme.colorScheme.primary,
        )
        Text(
            text = commit.subject,
            style = WebTermType.metaMono,
            color = MaterialTheme.colorScheme.onSurface,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis,
            modifier = Modifier.weight(1f),
        )
    }
}

// ── Rows / helpers (reused from A23) ────────────────────────────────────────────────────────────────

@Composable
private fun WorktreeRow(worktree: WorktreeInfo, onRemove: (() -> Unit)?) {
    val label = worktree.branch ?: worktree.head?.let { "detached @ $it" } ?: "detached"
    WebTermCard(modifier = Modifier.fillMaxWidth()) {
        Column(verticalArrangement = Arrangement.spacedBy(Spacing.xs4)) {
            Row(horizontalArrangement = Arrangement.spacedBy(Spacing.sm8), verticalAlignment = Alignment.CenterVertically) {
                Text(text = label, style = WebTermType.metaMono, color = MaterialTheme.colorScheme.onSurface, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.weight(1f))
                if (worktree.isMain) Tag("main")
                if (worktree.isCurrent) Tag("current")
                if (worktree.locked == true) Tag("locked")
                if (onRemove != null && !worktree.isMain) TextButton(onClick = onRemove) { Text("删除") }
            }
            Text(text = worktree.path, style = WebTermType.metaMono, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1, overflow = TextOverflow.Ellipsis)
        }
    }
}

@Composable
private fun SessionRow(session: ProjectSessionRef) {
    WebTermCard(modifier = Modifier.fillMaxWidth()) {
        Row(horizontalArrangement = Arrangement.spacedBy(Spacing.sm8), verticalAlignment = Alignment.CenterVertically) {
            Text(
                text = session.title ?: "session",
                style = WebTermType.metaMono,
                color = MaterialTheme.colorScheme.onSurface,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
                modifier = Modifier.weight(1f),
            )
            Text(text = "👁 ${session.clientCount}", style = WebTermType.metaMono, color = MaterialTheme.colorScheme.onSurfaceVariant)
        }
    }
}

@Composable
private fun ClaudeMdBlock(text: String) {
    WebTermCard(modifier = Modifier.fillMaxWidth()) {
        Text(text = text, style = WebTermType.monoTabular(12), color = MaterialTheme.colorScheme.onSurface)
    }
}

@Composable
private fun Tag(text: String) {
    Text(text = text, style = WebTermType.metaMono, color = MaterialTheme.colorScheme.primary)
}

@Composable
private fun SectionTitle(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.titleSmall,
        color = MaterialTheme.colorScheme.onBackground,
        modifier = Modifier.padding(top = Spacing.sm8),
    )
}

@Composable
private fun EmptyLine(text: String) {
    Text(text = text, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
}

@Composable
private fun Failure(failure: ProjectDetailViewModel.Failure, onRetry: () -> Unit) {
    val message = when (failure) {
        ProjectDetailViewModel.Failure.PATH_INVALID -> "项目路径为空或不合法。"
        ProjectDetailViewModel.Failure.NOT_FOUND -> "项目不存在（路径可能已移动或删除）。"
        ProjectDetailViewModel.Failure.UNAVAILABLE -> "读取项目详情失败，请稍后再试。"
    }
    Centered {
        Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(Spacing.sm8)) {
            Text(text = message, color = MaterialTheme.colorScheme.onBackground)
            TextButton(onClick = onRetry) { Text("重试") }
        }
    }
}

@Composable
private fun Centered(content: @Composable () -> Unit) {
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { content() }
}

@Preview(name = "ProjectDetailScreen — loaded")
@Composable
private fun ProjectDetailScreenPreview() {
    val detail = ProjectDetail(
        name = "Acme.Web.frontend",
        path = "/home/dev/acme-web",
        isGit = true,
        branch = "main",
        dirty = true,
        worktrees = emptyList(),
        sessions = emptyList(),
        hasClaudeMd = true,
        claudeMd = "# CLAUDE.md\n\nProject instructions…",
    )
    WebTermTheme {
        DetailBody(
            detail = detail,
            prChip = ProjectDetailViewModel.PrChip.Loaded(PrStatus(availability = PrAvailability.NO_PR)),
            recent = ProjectDetailViewModel.RecentCommits.Loaded(
                wang.yaojia.webterm.api.models.GitLogResult(
                    commits = listOf(CommitLogEntry("abc1234", 1, "Initial commit")),
                    truncated = false,
                ),
            ),
            worktree = null,
            onOpenClaude = {},
        )
    }
}
