// 14D 听写页（dudu://dictate，键盘扩展 MicBar 调起）。
// 背景：键盘扩展进程内无法录音（1A spike：CoreAudio 2003329396，平台硬限制），
// 用户在键盘上按一下麦克风 → deep link 到本页说话 → 定稿写剪贴板 + App Group →
// 手动切回原 App（iOS 无自动跳回 API），dudu 键盘自动上屏（剪贴板可手动粘贴兜底）。
//
// 设计（design/ 硬规则）：全屏深色玻璃 overlayBg（= rgba(24,26,34,.95) 同源 token）；
// final 亮 / partial 灰流式显示；波形 pattern 12 值仅录音中；
// 本屏唯一蓝色主按钮是 MicBar idle 态（guest/quota 拦截页则是"去登录/去充值"），
// "完成"为中性描边次按钮；文案短句无句号、"·"分隔。
import AVFoundation
import SwiftUI

struct DictationView: View {
    @EnvironmentObject private var account: AccountStore
    @EnvironmentObject private var router: AppRouter
    @Environment(\.dismiss) private var dismiss
    @StateObject private var controller = DictationController()

    @State private var pressing = false
    @State private var cancelArmed = false
    @State private var micDenied = false

    var body: some View {
        ZStack {
            DuduTheme.overlayBg.ignoresSafeArea()
            switch account.state {
            case .guest:
                // guest 拦截：识别需要登录态（WS 握手要 token），先引导去登录
                gatePrompt(title: "登录后开始用",
                           subtitle: "先登录 dudu · 回来接着说",
                           buttonTitle: "去登录") {
                    dismiss()
                    router.showLogin = true
                }
            case .quota:
                // quota 拦截：试用 + 余额均尽，引导去充值
                gatePrompt(title: "时长用完了",
                           subtitle: "充值后接着说",
                           buttonTitle: "去充值") {
                    dismiss()
                    router.path = NavigationPath([AppRouter.Route.purchase])
                }
            case .ok, .trial:
                dictation
            }
        }
        .onAppear {
            controller.account = account
            micDenied = AVAudioApplication.shared.recordPermission == .denied
        }
        .onDisappear { controller.teardown() }
    }

    // MARK: - 听写主界面

    private var dictation: some View {
        VStack(spacing: DuduTheme.space4) {
            header
            transcript
            statusLine
            if controller.errorCode == ApiError.quotaExceeded {
                quotaButton
            }
            micBar
            doneButton
        }
        .padding(.horizontal, DuduTheme.space5)
        .padding(.top, DuduTheme.space6)
        .padding(.bottom, DuduTheme.space5)
        .frame(maxWidth: 560) // iPad 收窄居中
        .frame(maxWidth: .infinity)
    }

    private var header: some View {
        VStack(spacing: DuduTheme.space2) {
            Text("dudu 听写")
                .font(.system(size: DuduTheme.textXl, weight: .semibold, design: .rounded))
                .foregroundStyle(DuduTheme.overlayText)
            Text("说完自动放进剪贴板 · 回到原来的 App 粘贴上屏")
                .font(.system(size: DuduTheme.textSm))
                .foregroundStyle(DuduTheme.overlayText2)
                .multilineTextAlignment(.center)
        }
    }

    /// 流式文本：final 亮（overlayText）+ partial 灰（overlayText2）
    private var transcript: some View {
        ScrollView {
            Group {
                if controller.phase == .done {
                    Text(controller.committedText)
                        .foregroundColor(DuduTheme.overlayText)
                } else if controller.finalText.isEmpty && controller.partialText.isEmpty {
                    Text(controller.phase == .recording ? "聆听中…" : "按住下面说话")
                        .foregroundColor(DuduTheme.overlayText3)
                } else {
                    (Text(controller.finalText).foregroundColor(DuduTheme.overlayText)
                        + Text(controller.partialText).foregroundColor(DuduTheme.overlayText2))
                }
            }
            .font(.system(size: DuduTheme.textXl))
            .lineSpacing(6)
            .frame(maxWidth: .infinity, alignment: .topLeading)
            .padding(.vertical, DuduTheme.space2)
        }
        .frame(maxHeight: .infinity)
    }

    /// 状态行：录音计时 / 定稿中 / 已复制 / 错误文案
    @ViewBuilder
    private var statusLine: some View {
        switch controller.phase {
        case .recording:
            Text(String(format: "%02d:%02d",
                        controller.elapsedSeconds / 60, controller.elapsedSeconds % 60))
                .font(.system(size: DuduTheme.textBase, weight: .medium).monospacedDigit())
                .foregroundStyle(DuduTheme.positive)
        case .finishing:
            Text("正在定稿")
                .font(.system(size: DuduTheme.textSm))
                .foregroundStyle(DuduTheme.overlayText2)
        case .done:
            Text("已复制 · 回到原 App 粘贴")
                .font(.system(size: DuduTheme.textBase, weight: .medium))
                .foregroundStyle(DuduTheme.positive)
        case .failed:
            Text(controller.errorText ?? "出错了 · 再试一次")
                .font(.system(size: DuduTheme.textSm))
                .foregroundStyle(DuduTheme.danger)
        case .idle:
            if micDenied {
                Button(action: openAppSettings) {
                    Text("需要麦克风权限 · 去设置开启")
                        .font(.system(size: DuduTheme.textSm))
                        .foregroundStyle(DuduTheme.warning)
                }
                .buttonStyle(.plain)
            } else {
                Text("最长 3 分钟 · 上滑取消")
                    .font(.system(size: DuduTheme.textSm))
                    .foregroundStyle(DuduTheme.overlayText3)
            }
        }
    }

    /// quota 错误（识别中途用尽）补充充值入口（描边次按钮，非本屏主按钮）
    private var quotaButton: some View {
        Button {
            dismiss()
            router.path = NavigationPath([AppRouter.Route.purchase])
        } label: {
            Text("去购买时长")
                .font(.system(size: DuduTheme.textMd, weight: .medium))
                .foregroundStyle(DuduTheme.overlayText)
                .padding(.horizontal, DuduTheme.space5)
                .frame(height: DuduTheme.controlMd)
                .overlay(Capsule().strokeBorder(DuduTheme.overlayText3))
                .contentShape(Capsule())
        }
        .buttonStyle(.plain)
    }

    // MARK: - MicBar（按住说话；波形仅录音中，bars=12 height=24）

    private var micBar: some View {
        HStack(spacing: DuduTheme.space2) {
            if controller.phase == .recording {
                WaveformView(bars: 12, height: 24)
                    .foregroundStyle(Color.white.opacity(0.95))
            } else {
                Image(systemName: "mic")
                    .font(.system(size: 22))
            }
            Text(micLabel)
                .font(.system(size: DuduTheme.textLg, weight: .semibold))
        }
        .foregroundStyle(DuduTheme.textOnAccent)
        .frame(maxWidth: .infinity)
        .frame(height: 64)
        .background(Capsule().fill(micBackground))
        .scaleEffect(pressing ? 0.97 : 1)
        .animation(.easeOut(duration: 0.12), value: pressing)
        .contentShape(Capsule())
        .gesture(micGesture)
    }

    private var micLabel: String {
        switch controller.phase {
        case .recording:
            return cancelArmed ? "松开取消" : "松开完成 · 上滑取消"
        case .finishing:
            return "正在定稿"
        default:
            return "按住说话"
        }
    }

    private var micBackground: Color {
        switch controller.phase {
        case .recording:
            return cancelArmed ? DuduTheme.danger : DuduTheme.positive
        case .finishing:
            return DuduTheme.overlayText3
        default:
            return pressing ? DuduTheme.accentPress : DuduTheme.accent
        }
    }

    /// 按住开始 / 松开结束 / 上滑（48pt 阈值）武装取消 —— 与键盘扩展 14C 同手势
    private var micGesture: some Gesture {
        DragGesture(minimumDistance: 0)
            .onChanged { value in
                if !pressing {
                    pressing = true
                    cancelArmed = false
                    micDown()
                }
                cancelArmed = value.translation.height < -48
            }
            .onEnded { _ in
                pressing = false
                controller.stop(cancelled: cancelArmed) // 未在录音时是 no-op
                cancelArmed = false
            }
    }

    private func micDown() {
        switch AVAudioApplication.shared.recordPermission {
        case .granted:
            micDenied = false
            controller.start(token: account.token ?? "")
        case .undetermined:
            // 首次：弹系统授权框，授权后用户再按一次开始
            AVAudioApplication.requestRecordPermission { granted in
                DispatchQueue.main.async { micDenied = !granted }
            }
        case .denied:
            micDenied = true
        @unknown default:
            break
        }
    }

    // MARK: - 完成（中性次按钮；本屏唯一蓝色主按钮是 MicBar）

    private var doneButton: some View {
        Button { dismiss() } label: {
            Text("完成")
                .font(.system(size: DuduTheme.textLg, weight: .medium))
                .foregroundStyle(DuduTheme.overlayText)
                .frame(maxWidth: .infinity)
                .frame(height: DuduTheme.controlLg)
                .overlay(Capsule().strokeBorder(DuduTheme.overlayText3))
                .contentShape(Capsule())
        }
        .buttonStyle(.plain)
    }

    // MARK: - guest / quota 拦截页（此时屏内唯一蓝色主按钮是引导按钮）

    private func gatePrompt(title: String, subtitle: String, buttonTitle: String,
                            action: @escaping () -> Void) -> some View {
        VStack(spacing: DuduTheme.space3) {
            Spacer()
            Image(systemName: "mic.slash")
                .font(.system(size: 32))
                .foregroundStyle(DuduTheme.overlayText3)
            Text(title)
                .font(.system(size: DuduTheme.textXl, weight: .semibold))
                .foregroundStyle(DuduTheme.overlayText)
            Text(subtitle)
                .font(.system(size: DuduTheme.textBase))
                .foregroundStyle(DuduTheme.overlayText2)
            Spacer()
            Button(action: action) {
                Text(buttonTitle)
                    .font(.system(size: DuduTheme.textLg, weight: .medium))
                    .foregroundStyle(DuduTheme.textOnAccent)
                    .frame(maxWidth: .infinity)
                    .frame(height: DuduTheme.controlXl)
                    .background(Capsule().fill(DuduTheme.accent))
            }
            Button { dismiss() } label: {
                Text("先不用")
                    .font(.system(size: DuduTheme.textMd))
                    .foregroundStyle(DuduTheme.overlayText2)
                    .frame(height: DuduTheme.controlLg)
            }
            .buttonStyle(.plain)
        }
        .padding(DuduTheme.space5)
        .frame(maxWidth: 560)
        .frame(maxWidth: .infinity)
    }

    private func openAppSettings() {
        if let url = URL(string: UIApplication.openSettingsURLString) {
            UIApplication.shared.open(url)
        }
    }
}

#Preview {
    DictationView()
        .environmentObject(AccountStore())
        .environmentObject(AppRouter())
}
