// 购买时长页（对照 doc/frontend-design.html 第七章 ③）：
// 余额卡（大数字）+ 三档时长包卡片（价格突出、选中 accent 边 + soft 底、省 x% 角标）
// + 底部主按钮"微信支付 ¥N"（金额随选中联动）。
// 流程：GET /v1/packs → POST /v1/orders(channel=app) → PayClient 拉起支付（MockPay 2s）
// → 轮询 GET /v1/orders/{id} 至 paid → GET /v1/me 刷新 → 成功态"已到账 · N 分钟"。
import SwiftUI

struct PurchaseView: View {
    @EnvironmentObject private var account: AccountStore
    @Environment(\.dismiss) private var dismiss
    @Environment(\.horizontalSizeClass) private var hSize

    private enum Phase: Equatable {
        case loading
        case ready
        case paying
        case success(minutes: Int)
        case loadFailed
    }

    @State private var phase: Phase = .loading
    @State private var packs: [Pack] = []
    @State private var selectedID: String?
    @State private var errorText: String?

    // TODO(wechat-pay): 商户号就绪后换 WechatPayClient（见 PayClient.swift）
    private let pay: PayClient = MockPay()

    private var selectedPack: Pack? { packs.first { $0.id == selectedID } }

    var body: some View {
        Group {
            switch phase {
            case .success(let minutes):
                successView(minutes: minutes)
            case .loading:
                ProgressView().frame(maxWidth: .infinity, maxHeight: .infinity)
            case .loadFailed:
                loadFailedView
            case .ready, .paying:
                form
            }
        }
        .background(DuduTheme.bgApp.ignoresSafeArea())
        .navigationTitle("购买时长")
        .navigationBarTitleDisplayMode(.inline)
        .task { await load() }
    }

    // MARK: - 表单

    private var form: some View {
        VStack(spacing: 0) {
            ScrollView {
                VStack(spacing: DuduTheme.space4) {
                    balanceCard
                    VStack(spacing: DuduTheme.space3) {
                        ForEach(packs) { pack in
                            packCard(pack)
                        }
                    }
                }
                .padding(DuduTheme.space4)
                .frame(maxWidth: hSize == .regular ? 640 : .infinity) // iPad 自适应收窄
                .frame(maxWidth: .infinity)
            }
            bottomBar
        }
    }

    private var balanceCard: some View {
        HStack(alignment: .firstTextBaseline, spacing: DuduTheme.space3) {
            VStack(alignment: .leading, spacing: 2) {
                Text("时长余额")
                    .font(.system(size: DuduTheme.textXs))
                    .foregroundStyle(DuduTheme.text3)
                Text("\(account.balanceSeconds / 60) 分钟")
                    .font(.system(size: DuduTheme.text2xl, weight: .bold).monospacedDigit())
                    .foregroundStyle(DuduTheme.text1)
            }
            Spacer()
            Text("时长不过期\n每天另有 3 分钟免费试用")
                .font(.system(size: DuduTheme.textXs))
                .foregroundStyle(DuduTheme.text3)
                .multilineTextAlignment(.trailing)
        }
        .padding(DuduTheme.space4)
        .background(DuduTheme.surfaceCard)
        .clipShape(RoundedRectangle(cornerRadius: DuduTheme.radiusLg))
        .overlay(RoundedRectangle(cornerRadius: DuduTheme.radiusLg).strokeBorder(DuduTheme.border1))
    }

    private func packCard(_ pack: Pack) -> some View {
        let selected = pack.id == selectedID
        return Button {
            selectedID = pack.id
        } label: {
            HStack(spacing: DuduTheme.space3) {
                VStack(alignment: .leading, spacing: 2) {
                    Text("\(pack.minutes) 分钟")
                        .font(.system(size: DuduTheme.textLg, weight: .semibold))
                        .foregroundStyle(DuduTheme.text1)
                    Text(pack.unitDesc)
                        .font(.system(size: DuduTheme.textXs))
                        .foregroundStyle(DuduTheme.text3)
                }
                Spacer()
                if let tag = pack.tag, !tag.isEmpty {
                    Text(tag)
                        .font(.system(size: DuduTheme.textXs, weight: .medium))
                        .foregroundStyle(DuduTheme.warning)
                        .padding(.horizontal, 8)
                        .padding(.vertical, 3)
                        .background(Capsule().fill(DuduTheme.warningSoft))
                }
                // 价格数字突出（24/700）
                Text(priceText(pack.priceCents))
                    .font(.system(size: DuduTheme.text2xl, weight: .bold).monospacedDigit())
                    .foregroundStyle(selected ? DuduTheme.accentText : DuduTheme.text1)
            }
            .padding(DuduTheme.space4)
            .background(selected ? DuduTheme.accentSoft : DuduTheme.surfaceCard)
            .clipShape(RoundedRectangle(cornerRadius: DuduTheme.radiusLg))
            .overlay(
                RoundedRectangle(cornerRadius: DuduTheme.radiusLg)
                    .strokeBorder(selected ? DuduTheme.accent : DuduTheme.border1,
                                  lineWidth: selected ? 1.5 : 1)
            )
        }
        .buttonStyle(.plain)
    }

    private var bottomBar: some View {
        VStack(spacing: DuduTheme.space2) {
            if let errorText {
                Text(errorText)
                    .font(.system(size: DuduTheme.textSm))
                    .foregroundStyle(DuduTheme.danger)
            }
            Button(action: buy) {
                HStack(spacing: DuduTheme.space2) {
                    if phase == .paying {
                        ProgressView().tint(DuduTheme.textOnAccent)
                    }
                    Text(phase == .paying ? "等待支付结果" : payButtonTitle)
                        .font(.system(size: DuduTheme.textLg, weight: .medium))
                }
                .foregroundStyle(DuduTheme.textOnAccent)
                .frame(maxWidth: .infinity)
                .frame(height: DuduTheme.controlLg)
                .background(DuduTheme.accent.opacity(phase == .paying || selectedPack == nil ? 0.5 : 1))
                .clipShape(RoundedRectangle(cornerRadius: DuduTheme.radiusSm))
            }
            .disabled(phase == .paying || selectedPack == nil)
            Text("支付后立即到账 · 时长不过期")
                .font(.system(size: DuduTheme.textXs))
                .foregroundStyle(DuduTheme.text3)
        }
        .padding(.horizontal, DuduTheme.space4)
        .padding(.vertical, DuduTheme.space3)
        .frame(maxWidth: hSize == .regular ? 640 : .infinity)
        .frame(maxWidth: .infinity)
        .background(DuduTheme.bgApp)
    }

    private var payButtonTitle: String {
        guard let pack = selectedPack else { return "微信支付" }
        return "微信支付 ¥" + priceNumber(pack.priceCents)
    }

    private func priceText(_ cents: Int) -> String { "¥" + priceNumber(cents) }

    private func priceNumber(_ cents: Int) -> String {
        cents % 100 == 0 ? "\(cents / 100)" : String(format: "%.2f", Double(cents) / 100)
    }

    // MARK: - 加载失败 / 成功态

    private var loadFailedView: some View {
        VStack(spacing: DuduTheme.space3) {
            Text("时长包加载失败")
                .font(.system(size: DuduTheme.textMd))
                .foregroundStyle(DuduTheme.text2)
            Button("重试") {
                phase = .loading
                Task { await load() }
            }
            .font(.system(size: DuduTheme.textMd, weight: .medium))
            .foregroundStyle(DuduTheme.accentText)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }

    private func successView(minutes: Int) -> some View {
        VStack(spacing: DuduTheme.space4) {
            Spacer()
            ZStack {
                Circle().fill(DuduTheme.positiveSoft).frame(width: 56, height: 56)
                Image(systemName: "checkmark")
                    .font(.system(size: 24, weight: .semibold))
                    .foregroundStyle(DuduTheme.positive)
            }
            Text("已到账 · \(minutes) 分钟")
                .font(.system(size: DuduTheme.textLg, weight: .semibold))
                .foregroundStyle(DuduTheme.text1)
            Text("时长不过期，随时用")
                .font(.system(size: DuduTheme.textSm))
                .foregroundStyle(DuduTheme.text3)
            Spacer()
            Button {
                dismiss()
            } label: {
                Text("完成")
                    .font(.system(size: DuduTheme.textLg, weight: .medium))
                    .foregroundStyle(DuduTheme.textOnAccent)
                    .frame(maxWidth: .infinity)
                    .frame(height: DuduTheme.controlLg)
                    .background(DuduTheme.accent)
                    .clipShape(RoundedRectangle(cornerRadius: DuduTheme.radiusSm))
            }
            .padding(.horizontal, DuduTheme.space4)
            .padding(.bottom, DuduTheme.space3)
        }
        .frame(maxWidth: hSize == .regular ? 640 : .infinity)
        .frame(maxWidth: .infinity)
    }

    // MARK: - 数据流

    private func load() async {
        guard packs.isEmpty else { return }
        do {
            let resp = try await Api.client.packs()
            packs = resp.packs
            // 默认选带角标的推荐档，没有则选中间档
            selectedID = resp.packs.first { $0.tag?.isEmpty == false }?.id
                ?? resp.packs[safe: resp.packs.count / 2]?.id
            phase = .ready
        } catch {
            phase = .loadFailed
        }
    }

    private func buy() {
        guard let token = account.token, let pack = selectedPack, phase == .ready else { return }
        phase = .paying
        errorText = nil
        Task {
            do {
                let order = try await Api.client.createOrder(token: token, packID: pack.id,
                                                             channel: PayChannel.app)
                try await pay.pay(orderID: order.orderID, amountCents: pack.priceCents,
                                  params: order.payParams ?? [:])
                // 轮询订单至 paid（1s 间隔，最多 15 次）
                var paid = false
                for _ in 0..<15 {
                    let st = try await Api.client.orderStatus(token: token, orderID: order.orderID)
                    if st.status == OrderStatus.paid { paid = true; break }
                    if st.status == OrderStatus.closed { break }
                    try await Task.sleep(nanoseconds: 1_000_000_000)
                }
                guard paid else {
                    phase = .ready
                    errorText = "支付未完成，稍后再试"
                    return
                }
                if let me = try? await Api.client.me(token: token) {
                    account.applyMe(me)
                }
                MetricsQueue.shared.track(.purchaseSuccess, props: ["pack_id": .string(pack.id)])
                phase = .success(minutes: pack.minutes)
            } catch {
                phase = .ready
                if let apiErr = error as? ApiError, !apiErr.message.isEmpty {
                    errorText = apiErr.message
                } else {
                    errorText = "支付失败，稍后再试"
                }
            }
        }
    }
}

private extension Array {
    subscript(safe index: Int) -> Element? {
        indices.contains(index) ? self[index] : nil
    }
}

#Preview {
    NavigationStack { PurchaseView().environmentObject(AccountStore()) }
}
