package app.dudu.app

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
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.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
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.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import app.dudu.data.AccountRepository
import app.dudu.data.MetricsQueue
import app.dudu.design.DText
import app.dudu.design.LocalDuduPalette
import app.dudu.net.ApiException
import app.dudu.net.DuduApi
import app.dudu.pay.PayResult
import app.dudu.pay.payClient
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

/** 购买流程阶段。 */
private enum class BuyPhase { PICK, PAYING, POLLING, SUCCESS }

/**
 * 购买时长页（13C）：GET /v1/packs 渲染时长包 → POST /v1/orders（channel=app）→
 * PayClient（mock 2 秒成功）→ 轮询 GET /v1/orders/{id} 至 paid → 刷新 /v1/me →
 * 成功态"已到账 · N 分钟"。
 */
@Composable
fun BuyScreen(refreshKey: Int, onBack: () -> Unit) {
    val p = LocalDuduPalette.current
    val context = LocalContext.current
    val repo = remember { AccountRepository.get(context) }
    val metrics = remember { MetricsQueue.get(context) }
    val account by repo.snapshot.collectAsState()
    val scope = rememberCoroutineScope()

    var packs by remember { mutableStateOf<List<DuduApi.Pack>?>(null) }
    var packsError by remember { mutableStateOf<String?>(null) }
    var selected by remember { mutableStateOf<DuduApi.Pack?>(null) }
    var phase by remember { mutableStateOf(BuyPhase.PICK) }
    var payError by remember { mutableStateOf<String?>(null) }
    var paidMinutes by remember { mutableStateOf(0) }

    // 拉时长包（价格以接口返回为准，前端不写死）
    LaunchedEffect(Unit) {
        try {
            val list = DuduApi.packs()
            packs = list
            // 默认选中带角标的档（无则第一档）
            selected = list.firstOrNull { it.tag != null } ?: list.firstOrNull()
        } catch (e: ApiException) {
            packsError = e.message
        }
    }

    fun startPay() {
        val pack = selected ?: return
        val token = account.token ?: return
        phase = BuyPhase.PAYING
        payError = null
        scope.launch {
            try {
                // 1. 下单拿 app 支付参数
                val order = DuduApi.createOrder(token, pack.id)
                // 2. 拉起收银台（mock 2 秒后成功；TODO(wechat-pay) 换 OpenSDK）
                when (val r = payClient.pay(order.orderId, order.payParams)) {
                    is PayResult.Cancelled -> {
                        phase = BuyPhase.PICK
                        payError = "已取消支付，可重新发起"
                        return@launch
                    }
                    is PayResult.Failed -> {
                        phase = BuyPhase.PICK
                        payError = "支付失败，稍后再试"
                        return@launch
                    }
                    is PayResult.Success -> Unit
                }
                // 3. 轮询订单态至 paid（1s 间隔，最长 30s）
                phase = BuyPhase.POLLING
                var paid = false
                var attempts = 0
                while (attempts < 30) {
                    val st = DuduApi.orderStatus(token, order.orderId)
                    if (st.status == "paid") {
                        paid = true
                        break
                    }
                    if (st.status == "closed") {
                        phase = BuyPhase.PICK
                        payError = "订单已关闭，请重新下单"
                        return@launch
                    }
                    attempts++
                    delay(1000)
                }
                if (!paid) {
                    phase = BuyPhase.PICK
                    payError = "支付确认中，稍后在我的页查看余额"
                    return@launch
                }
                // 4. 刷新 /v1/me 余额
                runCatching {
                    val me = DuduApi.me(token)
                    repo.applyMe(
                        userId = me.userId,
                        nicknameMasked = me.nicknameMasked,
                        balanceSeconds = me.balanceSeconds,
                        trialDailyLimit = me.trialDailyLimit,
                        trialUsedToday = me.trialUsedToday,
                    )
                }
                metrics.track("purchase.success", mapOf("pack_id" to pack.id))
                paidMinutes = pack.minutes
                phase = BuyPhase.SUCCESS
            } catch (e: ApiException) {
                phase = BuyPhase.PICK
                payError = e.message
            }
        }
    }

    Column(
        Modifier
            .fillMaxSize()
            .background(p.bgApp)
            .systemBarsPadding()
            .verticalScroll(rememberScrollState())
            .padding(horizontal = 24.dp),
    ) {
        TopBar("购买时长", onBack = if (phase == BuyPhase.SUCCESS) null else onBack)
        VSpace(8)

        if (phase == BuyPhase.SUCCESS) {
            // ── 成功态 ──
            VSpace(64)
            Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
                SuccessCheckCircle()
                VSpace(16)
                DText("已到账 · $paidMinutes 分钟", 17.sp, p.text1, weight = FontWeight.SemiBold)
                VSpace(8)
                DText("时长余额 ${account.balanceSeconds / 60} 分钟 · 不过期", 13.sp, p.text2)
                VSpace(28)
                GhostButton("完成", onClick = onBack)
            }
            VSpace(40)
            return@Column
        }

        // ── 余额卡 ──
        DCard {
            Row(verticalAlignment = Alignment.CenterVertically) {
                Column(Modifier.weight(1f)) {
                    DText("时长余额", 13.sp, p.text3)
                    VSpace(4)
                    // TODO(font-outfit): 大数字应为 Outfit，暂用系统 mono
                    DText("${account.balanceSeconds / 60} 分钟", 24.sp, p.text1, weight = FontWeight.Bold, mono = true)
                }
                DText("时长不过期\n每天另有 ${account.trialDailyLimitSeconds / 60} 分钟免费试用", 12.sp, p.text3)
            }
        }
        VSpace(16)

        // ── 时长包卡片 ──
        when {
            packsError != null -> {
                DCard {
                    DText(packsError ?: "", 13.sp, p.danger)
                    VSpace(12)
                    GhostButton("重试") {
                        packsError = null
                        scope.launch {
                            try {
                                val list = DuduApi.packs()
                                packs = list
                                selected = list.firstOrNull { it.tag != null } ?: list.firstOrNull()
                            } catch (e: ApiException) {
                                packsError = e.message
                            }
                        }
                    }
                }
            }
            packs == null -> DText("加载中", 13.sp, p.text3)
            else -> {
                packs?.forEach { pack ->
                    PackCard(pack, selected?.id == pack.id) { selected = pack }
                    VSpace(12)
                }
            }
        }

        NoticeText(payError)
        VSpace(16)

        // ── 主按钮（金额随选中联动）──
        val pack = selected
        val payText = when {
            phase == BuyPhase.PAYING -> "正在拉起微信支付"
            phase == BuyPhase.POLLING -> "等待支付确认"
            pack != null -> "微信支付 ¥" + formatYuan(pack.priceCents)
            else -> "微信支付"
        }
        PrimaryButton(
            payText,
            enabled = pack != null && account.token != null,
            loading = phase == BuyPhase.PAYING || phase == BuyPhase.POLLING,
        ) { startPay() }
        VSpace(10)
        DText(
            "支付后立即到账 · 时长不过期", 12.sp, p.text3,
            modifier = Modifier.fillMaxWidth(),
            textAlign = androidx.compose.ui.text.style.TextAlign.Center,
        )
        VSpace(40)
    }
}

/** 时长包卡片：分钟数 + 价格（数字突出）+ 单价注 + 省 x% 角标，选中 accent 边 + soft 底。 */
@Composable
private fun PackCard(pack: DuduApi.Pack, selected: Boolean, onSelect: () -> Unit) {
    val p = LocalDuduPalette.current
    val src = remember { MutableInteractionSource() }
    Row(
        Modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(14.dp))
            .background(if (selected) p.accentSoft else p.surfaceCard)
            .border(
                width = if (selected) 1.5.dp else 1.dp,
                color = if (selected) p.accent else p.border1,
                shape = RoundedCornerShape(14.dp),
            )
            .clickable(interactionSource = src, indication = null, onClick = onSelect)
            .padding(16.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Column(Modifier.weight(1f)) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                DText("${pack.minutes} 分钟", 17.sp, p.text1, weight = FontWeight.SemiBold, mono = true)
                pack.tag?.let {
                    HSpace(8)
                    Badge(it, BadgeKind.WARNING)
                }
            }
            VSpace(4)
            DText(pack.unitDesc, 12.sp, p.text3)
        }
        // TODO(font-outfit): 价格数字应为 Outfit，暂用系统 mono
        DText("¥" + formatYuan(pack.priceCents), 20.sp, if (selected) p.accentText else p.text1, weight = FontWeight.Bold, mono = true)
    }
}

/** 分转元：900 → "9"，3950 → "39.5"。 */
private fun formatYuan(cents: Int): String {
    val yuan = cents / 100
    val rem = cents % 100
    return when {
        rem == 0 -> "$yuan"
        rem % 10 == 0 -> "$yuan.${rem / 10}"
        else -> "$yuan." + rem.toString().padStart(2, '0')
    }
}
