import SwiftUI

/// 推理引擎设置:在 MNN(CPU/SME2,考核路径)与 MLX(GPU,兜底)间切换,并展示 SME2 探测状态。
/// 切换只改持久化选择;下一次 AI 调用(prepare/generate)按新引擎加载。
struct InferenceSettingsView: View {
    @AppStorage("kk.inferenceEngine") private var engineRaw = EnginePreference.auto.rawValue
    @State private var modelService = ModelDownloadService.shared

    private var selected: EnginePreference {
        EnginePreference(rawValue: engineRaw) ?? .auto
    }

    /// 性能自检需要模型就绪(MNN 主或 MLX 兜底任一)。
    private var modelReady: Bool {
        modelService.states[.mnnLLM]?.phase == .ready
            || modelService.states[.llm]?.phase == .ready
    }

    var body: some View {
        ScrollView {
            VStack(spacing: 12) {
                HStack {
                    Text("推理引擎")
                        .font(.tjTitle())
                        .foregroundStyle(Tj.Palette.text)
                    Spacer()
                }
                .padding(.top, 4)
                .padding(.bottom, 6)

                ForEach(EnginePreference.allCases, id: \.self) { engine in
                    engineRow(engine)
                }

                sme2Card
                selfTestSection
                noteCard
            }
            .padding(.horizontal, 16)
            .padding(.vertical, 20)
        }
        .background(Tj.Palette.sand.ignoresSafeArea())
        .onAppear { modelService.refreshStates() }
    }

    /// 性能自检入口:用当前选中的引擎跑固定 prompt,实测并按后端归档对比。
    /// 模型未就绪时显示「前往下载」提示而非死链。
    @ViewBuilder
    private var selfTestSection: some View {
        if modelReady {
            NavigationLink {
                ModelSelfTestView()
            } label: {
                HStack(spacing: 12) {
                    ZStack {
                        Circle().fill(Tj.Palette.sand2)
                        Image(systemName: "gauge.with.needle")
                            .font(.tjScaled(18))
                            .foregroundStyle(Tj.Palette.ink)
                    }
                    .frame(width: 44, height: 44)
                    VStack(alignment: .leading, spacing: 2) {
                        Text("性能自检")
                            .font(.tjScaled(15, weight: .semibold))
                            .foregroundStyle(Tj.Palette.text)
                        Text("用上方选中的引擎跑固定 prompt,实测 prefill / 生成 tok/s")
                            .font(.tjScaled(12))
                            .foregroundStyle(Tj.Palette.text3)
                            .lineLimit(2)
                    }
                    Spacer()
                    Image(systemName: "chevron.right")
                        .font(.tjScaled(13, weight: .semibold))
                        .foregroundStyle(Tj.Palette.text3)
                }
                .padding(14)
                .tjCard()
            }
            .buttonStyle(.plain)
        } else {
            HStack(spacing: 12) {
                ZStack {
                    Circle().fill(Tj.Palette.sand2)
                    Image(systemName: "gauge.with.needle")
                        .font(.tjScaled(18))
                        .foregroundStyle(Tj.Palette.text2)
                }
                .frame(width: 44, height: 44)
                VStack(alignment: .leading, spacing: 2) {
                    Text("性能自检")
                        .font(.tjScaled(15, weight: .semibold))
                        .foregroundStyle(Tj.Palette.text)
                    Text("模型未就绪,前往「模型管理」下载后可用")
                        .font(.tjScaled(12))
                        .foregroundStyle(Tj.Palette.text3)
                        .lineLimit(2)
                }
                Spacer()
            }
            .padding(14)
            .tjCard()
            .opacity(0.55)
        }
    }

    private func engineRow(_ engine: EnginePreference) -> some View {
        let available = isAvailable(engine)
        let isOn = (selected == engine)
        return Button {
            guard available else { return }
            engineRaw = engine.rawValue
        } label: {
            HStack(spacing: 12) {
                ZStack {
                    Circle().fill(isOn ? Tj.Palette.amber.opacity(0.25) : Tj.Palette.sand2)
                    Image(systemName: iconName(engine))
                        .font(.tjScaled(18))
                        .foregroundStyle(isOn ? Tj.Palette.ink : Tj.Palette.text2)
                }
                .frame(width: 44, height: 44)

                VStack(alignment: .leading, spacing: 2) {
                    Text(engine.displayName)
                        .font(.tjScaled(15, weight: .semibold))
                        .foregroundStyle(Tj.Palette.text)
                    Text(subtitle(engine, available: available))
                        .font(.tjScaled(12))
                        .foregroundStyle(Tj.Palette.text3)
                        .lineLimit(2)
                }
                Spacer()
                if isOn {
                    Image(systemName: "checkmark.circle.fill")
                        .font(.tjScaled(18))
                        .foregroundStyle(Tj.Palette.leaf)
                }
            }
            .padding(14)
            .tjCard()
            .opacity(available ? 1 : 0.45)
        }
        .buttonStyle(.plain)
        .disabled(!available)
    }

    /// .auto 永远可用;具体引擎看自身可用性。
    private func isAvailable(_ engine: EnginePreference) -> Bool {
        switch engine {
        case .auto: return true
        case .mnn:  return InferenceEngine.mnn.isAvailable
        case .mlx:  return InferenceEngine.mlx.isAvailable
        }
    }

    private func iconName(_ engine: EnginePreference) -> String {
        switch engine {
        case .auto: return "wand.and.stars"
        case .mnn:  return "cpu.fill"
        case .mlx:  return "bolt.fill"
        }
    }

    private func subtitle(_ engine: EnginePreference, available: Bool) -> String {
        switch engine {
        case .auto:
            // 显示自动解析后实际命中的引擎,让用户看清「这台机选了什么」。
            let resolved = engine.resolved
            if resolved == .mnn {
                return InferenceEngine.cpuSupportsSME2
                    ? String(appLoc: "按本机配置选择 · 当前 MNN + SME2")
                    : String(appLoc: "按本机配置选择 · 当前 MNN(NEON)")
            } else {
                return String(appLoc: "按本机配置选择 · 当前 MLX(MNN 不可用)")
            }
        case .mnn:
            if !available { return String(appLoc: "本设备/模拟器不可用,自动回退 MLX") }
            return InferenceEngine.cpuSupportsSME2
                ? String(appLoc: "端侧 CPU + SME2 加速 · 挑战赛考核路径")
                : String(appLoc: "端侧 CPU(本机无 SME2,NEON 回退)")
        case .mlx:
            return String(appLoc: "Metal GPU · 兜底 / 对照")
        }
    }

    private var sme2Card: some View {
        let sme2 = InferenceEngine.cpuSupportsSME2
        return HStack(spacing: 12) {
            ZStack {
                Circle().fill(sme2 ? Tj.Palette.leafSoft : Tj.Palette.sand2)
                Image(systemName: sme2 ? "checkmark.seal.fill" : "minus.circle")
                    .font(.tjScaled(18))
                    .foregroundStyle(sme2 ? Tj.Palette.ink : Tj.Palette.text2)
            }
            .frame(width: 44, height: 44)
            VStack(alignment: .leading, spacing: 2) {
                Text("Arm SME2")
                    .font(.tjScaled(15, weight: .medium))
                    .foregroundStyle(Tj.Palette.text)
                Text(sme2 ? String(appLoc: "本设备支持,MNN 已启用 SME2 加速")
                          : String(appLoc: "本设备不支持(需 A19/iPhone 17+)"))
                    .font(.tjScaled(12))
                    .foregroundStyle(Tj.Palette.text3)
            }
            Spacer()
        }
        .padding(14)
        .tjCard()
    }

    private var noteCard: some View {
        Text("MNN 在端侧 CPU 上以 Arm SME2 指令集加速 Qwen 推理(本地、不上云)。切换后下一次 AI 调用生效。")
            .font(.tjScaled(12))
            .foregroundStyle(Tj.Palette.text3)
            .frame(maxWidth: .infinity, alignment: .leading)
            .padding(14)
            .tjCard()
    }
}

#Preview {
    InferenceSettingsView()
}
