//
//  FirstViewController.swift
//  Dialog_Demo
//
//  对话配置入口页面
//

import UIKit
import AVFoundation
import SnapKit
import multimodal_dialog
import MultimodalDialogTongyiMetathings

// MARK: - FirstViewController
class FirstViewController: UIViewController {

    // MARK: - Properties

    /// WebSocket 默认地址
    private let wsDefaultURL = "wss://dashscope.aliyuncs.com/api-ws/v1/inference"

    // MARK: - UI Components

    private lazy var scrollView: UIScrollView = {
        let sv = UIScrollView()
        sv.showsVerticalScrollIndicator = false
        sv.keyboardDismissMode = .onDrag
        return sv
    }()

    private lazy var contentView: UIView = {
        let v = UIView()
        return v
    }()

    // 顶部标题区
    private lazy var headerIcon: UIImageView = {
        let iv = UIImageView()
        let config = UIImage.SymbolConfiguration(pointSize: 50, weight: .medium)
        iv.image = UIImage(systemName: "waveform.circle.fill", withConfiguration: config)
        iv.tintColor = UIColor(red: 0x4A/255.0, green: 0x9E/255.0, blue: 0xFF/255.0, alpha: 1.0)
        iv.contentMode = .scaleAspectFit
        return iv
    }()

    private lazy var titleLabel: UILabel = {
        let label = UILabel()
        label.text = "多模态对话"
        label.font = UIFont.systemFont(ofSize: 24, weight: .bold)
        label.textAlignment = .center
        label.textColor = .label
        return label
    }()

    private lazy var subtitleLabel: UILabel = {
        let label = UILabel()
        label.text = "Multimodal Dialog Demo"
        label.font = UIFont.systemFont(ofSize: 14, weight: .regular)
        label.textAlignment = .center
        label.textColor = .secondaryLabel
        return label
    }()

    // 卡片1 - 基础配置
    private lazy var basicCard: UIView = createCard()
    private lazy var basicTitleLabel: UILabel = createCardTitle("基础配置")
    private lazy var workspaceIdField: UITextField = createInputField(placeholder: "")
    private lazy var appIdField: UITextField = createInputField(placeholder: "")
    private lazy var apiKeyField: UITextField = createInputField(placeholder: "")


    // 卡片2 - 对话模式
    private lazy var modeCard: UIView = createCard()
    private lazy var modeTitleLabel: UILabel = createCardTitle("对话模式")
    private lazy var modeSegment: UISegmentedControl = {
        let sc = UISegmentedControl(items: ["duplex", "tap2talk", "push2talk"])
        sc.selectedSegmentIndex = 0 // 默认 duplex
        return sc
    }()
    private lazy var modeHintLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 12)
        label.textColor = .tertiaryLabel
        label.numberOfLines = 0
        label.text = "duplex：全双工语音打断"
        return label
    }()

    // 卡片3 - 高级配置
    private lazy var advancedCard: UIView = createCard()
    private lazy var advancedTitleLabel: UILabel = createCardTitle("高级配置")
    private lazy var serverUrlField: UITextField = createInputField(placeholder: "wss://dashscope.aliyuncs.com/api-ws/v1/inference")
    private lazy var imageUrlField: UITextField = createInputField(placeholder: "https://help-static-aliyun-doc.aliyuncs.com/assets/img/zh-CN/7043267371/p909896.png")

    // 卡片4 - 计费方式（License 模式接入 MultimodalDialogTongyiMetathings）
    private lazy var billingCard: UIView = createCard()
    private lazy var billingTitleLabel: UILabel = createCardTitle("计费方式")
    private lazy var billingSegment: UISegmentedControl = {
        let sc = UISegmentedControl(items: ["后付费", "License计费"])
        sc.selectedSegmentIndex = 0
        return sc
    }()
    private lazy var billingHintLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 12)
        label.textColor = .tertiaryLabel
        label.numberOfLines = 0
        label.text = "后付费：使用 API Key 直接鉴权"
        return label
    }()
    private lazy var appSecretField: UITextField = createInputField(placeholder: "App Secret（License 模式必填）")
    private lazy var appSecretRow: UIView = createFormRow(label: "App Secret", field: appSecretField)

    /// License 模式下使用的设备唯一标识
    private var mDeviceName: String = ""
    /// 当前消息提示弹窗
    private var messageAlert: UIAlertController?

    // 开始按钮
    private lazy var startButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("开始对话", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
        btn.layer.cornerRadius = 25
        btn.clipsToBounds = true
        btn.addTarget(self, action: #selector(startButtonTapped), for: .touchUpInside)
        btn.addTarget(self, action: #selector(buttonTouchDown), for: .touchDown)
        btn.addTarget(self, action: #selector(buttonTouchUp), for: [.touchUpInside, .touchUpOutside, .touchCancel])
        return btn
    }()

    private let gradientLayer = CAGradientLayer()

    // MARK: - Lifecycle

    init(endpointUrl: String) {
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemGroupedBackground
        setupLayout()
        setupKeyboardDismiss()
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        gradientLayer.frame = startButton.bounds
    }

    // MARK: - Layout Setup

    private func setupLayout() {
        view.addSubview(scrollView)
        scrollView.addSubview(contentView)

        scrollView.snp.makeConstraints { make in
            make.edges.equalTo(view.safeAreaLayoutGuide)
        }

        contentView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalToSuperview()
        }

        setupHeader()
        setupBasicCard()
        setupModeCard()
        setupBillingCard()
        setupAdvancedCard()
        setupStartButton()
    }

    private func setupModeCard() {
        contentView.addSubview(modeCard)
        modeCard.addSubview(modeTitleLabel)
        modeCard.addSubview(modeSegment)
        modeCard.addSubview(modeHintLabel)

        modeCard.snp.makeConstraints { make in
            make.top.equalTo(basicCard.snp.bottom).offset(12)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        modeTitleLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        modeSegment.snp.makeConstraints { make in
            make.top.equalTo(modeTitleLabel.snp.bottom).offset(12)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
            make.height.equalTo(32)
        }

        modeHintLabel.snp.makeConstraints { make in
            make.top.equalTo(modeSegment.snp.bottom).offset(8)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
            make.bottom.equalToSuperview().offset(-16)
        }

        modeSegment.addTarget(self, action: #selector(modeSegmentChanged), for: .valueChanged)
    }

    @objc private func modeSegmentChanged() {
        switch modeSegment.selectedSegmentIndex {
        case 1:
            modeHintLabel.text = "tap2talk：点击开始说话，自动收音结束"
        case 2:
            modeHintLabel.text = "push2talk：按住说话，抬起结束"
        default:
            modeHintLabel.text = "duplex：全双工语音打断"
        }
    }

    private var selectedDialogMode: DialogMode {
        switch modeSegment.selectedSegmentIndex {
        case 1: return .tap2talk
        case 2: return .push2talk
        default: return .duplex
        }
    }

    private func setupHeader() {
        contentView.addSubview(headerIcon)
        contentView.addSubview(titleLabel)
        contentView.addSubview(subtitleLabel)

        headerIcon.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(30)
            make.centerX.equalToSuperview()
            make.width.height.equalTo(50)
        }

        titleLabel.snp.makeConstraints { make in
            make.top.equalTo(headerIcon.snp.bottom).offset(12)
            make.centerX.equalToSuperview()
        }

        subtitleLabel.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(4)
            make.centerX.equalToSuperview()
        }
    }

    private func setupBasicCard() {
        contentView.addSubview(basicCard)
        basicCard.addSubview(basicTitleLabel)

        basicCard.snp.makeConstraints { make in
            make.top.equalTo(subtitleLabel.snp.bottom).offset(24)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        basicTitleLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        let row1 = createFormRow(label: "WorkspaceId", field: workspaceIdField)
        let row2 = createFormRow(label: "App ID", field: appIdField)
        let row3 = createFormRow(label: "API Key", field: apiKeyField)

        basicCard.addSubview(row1)
        basicCard.addSubview(row2)
        basicCard.addSubview(row3)

        row1.snp.makeConstraints { make in
            make.top.equalTo(basicTitleLabel.snp.bottom).offset(12)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        row2.snp.makeConstraints { make in
            make.top.equalTo(row1.snp.bottom).offset(10)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        row3.snp.makeConstraints { make in
            make.top.equalTo(row2.snp.bottom).offset(10)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
            make.bottom.equalToSuperview().offset(-16)
        }
    }

    private func setupBillingCard() {
        contentView.addSubview(billingCard)
        billingCard.addSubview(billingTitleLabel)
        billingCard.addSubview(billingSegment)
        billingCard.addSubview(billingHintLabel)
        billingCard.addSubview(appSecretRow)

        billingCard.snp.makeConstraints { make in
            make.top.equalTo(modeCard.snp.bottom).offset(12)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        billingTitleLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        billingSegment.snp.makeConstraints { make in
            make.top.equalTo(billingTitleLabel.snp.bottom).offset(12)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
            make.height.equalTo(32)
        }

        billingHintLabel.snp.makeConstraints { make in
            make.top.equalTo(billingSegment.snp.bottom).offset(8)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        appSecretRow.snp.makeConstraints { make in
            make.top.equalTo(billingHintLabel.snp.bottom).offset(10)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
            make.bottom.equalToSuperview().offset(-16)
        }

        // 默认后付费，隐藏 App Secret 输入行
        appSecretRow.isHidden = true
        billingSegment.addTarget(self, action: #selector(billingSegmentChanged), for: .valueChanged)
    }

    @objc private func billingSegmentChanged() {
        let isLicense = billingSegment.selectedSegmentIndex == 1
        appSecretRow.isHidden = !isLicense
        billingHintLabel.text = isLicense
            ? "License 计费：需填入 App Secret，首次使用会自动注册设备"
            : "后付费：使用 API Key 直接鉴权"
    }

    private func setupAdvancedCard() {
        contentView.addSubview(advancedCard)
        advancedCard.addSubview(advancedTitleLabel)

        advancedCard.snp.makeConstraints { make in
            make.top.equalTo(billingCard.snp.bottom).offset(12)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        advancedTitleLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        let row1 = createFormRow(label: "服务地址", field: serverUrlField)
        let row2 = createFormRow(label: "图片URL", field: imageUrlField)

        let imageHintLabel = UILabel()
        imageHintLabel.text = "VQA 测试使用"
        imageHintLabel.font = UIFont.systemFont(ofSize: 11)
        imageHintLabel.textColor = .tertiaryLabel

        advancedCard.addSubview(row1)
        advancedCard.addSubview(row2)
        advancedCard.addSubview(imageHintLabel)

        row1.snp.makeConstraints { make in
            make.top.equalTo(advancedTitleLabel.snp.bottom).offset(12)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        row2.snp.makeConstraints { make in
            make.top.equalTo(row1.snp.bottom).offset(10)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
        }

        imageHintLabel.snp.makeConstraints { make in
            make.top.equalTo(row2.snp.bottom).offset(4)
            // 与输入框左边对齐：容器左边16 + label 宽75 + 间距8
            make.leading.equalToSuperview().offset(16 + 75 + 8)
            make.trailing.equalToSuperview().offset(-16)
            make.bottom.equalToSuperview().offset(-16)
        }
    }

    private func setupStartButton() {
        contentView.addSubview(startButton)

        startButton.snp.makeConstraints { make in
            make.top.equalTo(advancedCard.snp.bottom).offset(24)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
            make.height.equalTo(50)
            make.bottom.equalToSuperview().offset(-20)
        }

        // 渐变背景
        gradientLayer.colors = [
            UIColor(red: 0x4A/255.0, green: 0x9E/255.0, blue: 0xFF/255.0, alpha: 1.0).cgColor,
            UIColor(red: 0x2D/255.0, green: 0x7D/255.0, blue: 0xD2/255.0, alpha: 1.0).cgColor
        ]
        gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
        gradientLayer.cornerRadius = 25
        startButton.layer.insertSublayer(gradientLayer, at: 0)

        // 阴影
        startButton.layer.shadowColor = UIColor(red: 0x4A/255.0, green: 0x9E/255.0, blue: 0xFF/255.0, alpha: 1.0).cgColor
        startButton.layer.shadowOpacity = 0.3
        startButton.layer.shadowOffset = CGSize(width: 0, height: 4)
        startButton.layer.shadowRadius = 8
        startButton.layer.masksToBounds = false
    }

    // MARK: - Factory Methods

    private func createCard() -> UIView {
        let card = UIView()
        card.backgroundColor = .white
        card.layer.cornerRadius = 12
        card.layer.shadowColor = UIColor.black.cgColor
        card.layer.shadowOpacity = 0.08
        card.layer.shadowRadius = 8
        card.layer.shadowOffset = CGSize(width: 0, height: 2)
        card.layer.masksToBounds = false
        return card
    }

    private func createCardTitle(_ text: String) -> UILabel {
        let label = UILabel()
        label.text = text
        label.font = UIFont.systemFont(ofSize: 15, weight: .semibold)
        label.textColor = .label
        return label
    }

    private func createInputField(placeholder: String) -> UITextField {
        let tf = UITextField()
        tf.placeholder = placeholder
        tf.font = UIFont.systemFont(ofSize: 14)
        tf.backgroundColor = UIColor.systemGray6
        tf.layer.cornerRadius = 8
        tf.clipsToBounds = true
        tf.borderStyle = .none
        tf.clearButtonMode = .whileEditing
        tf.returnKeyType = .next
        tf.delegate = self
        // 添加左侧内边距
        let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 0))
        tf.leftView = paddingView
        tf.leftViewMode = .always
        return tf
    }

    private func createFormRow(label text: String, field: UITextField) -> UIView {
        let container = UIView()
        let label = UILabel()
        label.text = text
        label.font = UIFont.systemFont(ofSize: 13)
        label.textColor = .secondaryLabel
        label.setContentHuggingPriority(.required, for: .horizontal)
        label.setContentCompressionResistancePriority(.required, for: .horizontal)

        container.addSubview(label)
        container.addSubview(field)

        label.snp.makeConstraints { make in
            make.leading.equalToSuperview()
            make.centerY.equalToSuperview()
            make.width.equalTo(75)
        }

        field.snp.makeConstraints { make in
            make.leading.equalTo(label.snp.trailing).offset(8)
            make.trailing.equalToSuperview()
            make.top.bottom.equalToSuperview()
            make.height.equalTo(38)
        }

        return container
    }

    // MARK: - Keyboard Handling

    private func setupKeyboardDismiss() {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
        tapGesture.cancelsTouchesInView = false
        view.addGestureRecognizer(tapGesture)
    }

    @objc private func dismissKeyboard() {
        view.endEditing(true)
    }

    // MARK: - Actions

    @objc private func buttonTouchDown() {
        UIView.animate(withDuration: 0.1) {
            self.startButton.transform = CGAffineTransform(scaleX: 0.96, y: 0.96)
            self.startButton.layer.shadowOpacity = 0.15
        }
    }

    @objc private func buttonTouchUp() {
        UIView.animate(withDuration: 0.1) {
            self.startButton.transform = .identity
            self.startButton.layer.shadowOpacity = 0.3
        }
    }

    @objc private func startButtonTapped() {
        if !checkAndRequestPermissions() {
            print("permission error")
            return
        }

        let workSpaceId = getTextOrPlaceholder(from: workspaceIdField)
        let host = getTextOrPlaceholder(from: serverUrlField)
        let apiKey = getTextOrPlaceholder(from: apiKeyField)
        let appId = getTextOrPlaceholder(from: appIdField)
        let img = getTextOrPlaceholder(from: imageUrlField)

        if workSpaceId.isEmpty || apiKey.isEmpty || appId.isEmpty {
            showAlertMessage("请配置必填参数再开始测试")
            return
        }

        if isLicenseMode {
            // License 计费：初始化 -> 检查注册 -> 获取 token -> 跳转
            let appSecret = getTextOrPlaceholder(from: appSecretField)
            if appSecret.isEmpty {
                showAlertMessage("请配置 App Secret 参数再开始测试")
                return
            }
            mDeviceName = DeviceInfoUtils.shared.getDeviceId() ?? "unknown_device"
            startLicenseFlow(host: host,
                             apiKey: apiKey,
                             workSpaceId: workSpaceId,
                             appId: appId,
                             appSecret: appSecret,
                             img: img)
        } else {
            // 后付费：直接跳转
            presentChat(host: host,
                        apiKey: apiKey,
                        workSpaceId: workSpaceId,
                        appId: appId,
                        img: img,
                        payMode: PayMode.payg.payMode)
        }
    }

    // MARK: - License Flow

    /// 是否选择了 License 计费模式
    private var isLicenseMode: Bool { billingSegment.selectedSegmentIndex == 1 }

    /// License 模式：初始化设备认证 -> 检查/注册 -> 获取 token -> 跳转 ChatViewController
    private func startLicenseFlow(host: String,
                                  apiKey: String,
                                  workSpaceId: String,
                                  appId: String,
                                  appSecret: String,
                                  img: String) {
        class DeviceInitCallback: InitCallBack {
            private let onComplete: (Bool, String?) -> Void
            init(onComplete: @escaping (Bool, String?) -> Void) { self.onComplete = onComplete }
            func success() { onComplete(true, nil) }
            func fail(error: ResultError) { onComplete(false, error.message) }
        }

        let initCallBack = DeviceInitCallback { [weak self] success, message in
            DispatchQueue.main.async {
                guard let self = self else { return }
                if success {
                    print("license: 初始化成功")
                    let registered = DeviceAuthClient.companion.instance.deviceIsRegistered()
                    if !registered {
                        self.deviceRegister(appId: appId,
                                            workspaceId: workSpaceId,
                                            appSecret: appSecret,
                                            deviceName: self.mDeviceName,
                                            onSuccess: {
                            self.fetchTokenAndPresent(host: host,
                                                      apiKey: apiKey,
                                                      workSpaceId: workSpaceId,
                                                      appId: appId,
                                                      img: img)
                        })
                    } else {
                        self.fetchTokenAndPresent(host: host,
                                                  apiKey: apiKey,
                                                  workSpaceId: workSpaceId,
                                                  appId: appId,
                                                  img: img)
                    }
                } else {
                    print("license: 初始化失败 \(message ?? "")")
                    self.showAlertMessage("初始化失败: \(message ?? "")")
                }
            }
        }

        let params = InitParams(appId: appId, appSecret: appSecret, deviceName: mDeviceName)
        DeviceAuthClient.companion.instance.initialize(params: params, callBack: initCallBack)
    }

    /// 设备注册
    private func deviceRegister(appId: String,
                                workspaceId: workSpaceId,
                                appSecret: String,
                                deviceName: String,
                                onSuccess: @escaping () -> Void) {
        let timestamp: () -> String = {
            let t = Date().timeIntervalSince1970 * 1000
            return "\(Int64(t))"
        }

        class DeviceRegisterCallback: DeviceRegisterCallBack {
            private let onComplete: (Bool, String?) -> Void
            init(onComplete: @escaping (Bool, String?) -> Void) { self.onComplete = onComplete }
            func success() { onComplete(true, "注册成功") }
            func fail(error: ResultError) { onComplete(false, error.message) }
        }

        let registerParams = DeviceRegisterParams(
            nonce: RandomHexUtils.shared.generateNormalHex(length: 26),
            appId: appId,
            workspaceId: workspaceId,
            deviceName: deviceName,
            payMode: PayMode.license.payMode,
            requestTime: timestamp(),
            signature: nil
        )

        let cb = DeviceRegisterCallback { [weak self] success, message in
            DispatchQueue.main.async {
                guard let self = self else { return }
                if success {
                    print("license: 设备注册成功")
                    onSuccess()
                } else {
                    self.showAlertMessage("设备注册失败: \(message ?? "")")
                }
            }
        }

        DeviceAuthClient.companion.instance.deviceRegister(params: registerParams,
                                                            callBack: cb,
                                                            completionHandler: { _ in })
    }

    /// 获取会话 token 并跳转
    private func fetchTokenAndPresent(host: String,
                                      apiKey: String,
                                      workSpaceId: String,
                                      appId: String,
                                      img: String) {
        let timestamp: () -> String = {
            let t = Date().timeIntervalSince1970 * 1000
            return "\(Int64(t))"
        }

        class TokenCallback: GetTokenCallBack {
            private let onComplete: (String?) -> Void
            init(onComplete: @escaping (String?) -> Void) { self.onComplete = onComplete }
            func success(tokenInfo: String?) { onComplete(tokenInfo) }
            func fail(error_ error: ResultError?) {
                print("getToken fail: \(error?.message ?? "unknown")")
                onComplete(nil)
            }
        }

        let getTokenParams = GenGetTokenParams(
            nonce: RandomHexUtils.shared.generateNormalHex(length: 26),
            appId: appId,
            apiKey: apiKey,
            deviceName: mDeviceName,
            payMode: PayMode.license.payMode,
            requestTime: timestamp(),
            signature: nil,
            tokenType: "MMI"
        )

        let tokenCb = TokenCallback { [weak self] data in
            DispatchQueue.main.async {
                guard let self = self else { return }
                guard let data = data,
                      let bytes = data.data(using: .utf8) else {
                    self.showAlertMessage("获取 token 失败")
                    return
                }
                do {
                    let json = try JSONSerialization.jsonObject(with: bytes)
                    if let dict = json as? [String: Any],
                       let dashToken = dict["dashToken"] as? String {
                        self.presentChat(host: host,
                                         apiKey: dashToken,
                                         workSpaceId: workSpaceId,
                                         appId: appId,
                                         img: img,
                                         payMode: PayMode.license.payMode)
                    } else {
                        self.showAlertMessage("token 解析失败")
                    }
                } catch {
                    self.showAlertMessage("JSON 解析失败: \(error)")
                }
            }
        }

        Task {
            do {
                try await DeviceAuthClient.companion.instance.getToken(params: getTokenParams, callBack: tokenCb)
            } catch {
                print("getToken error: \(error)")
            }
        }
    }

    /// 统一跳转到 ChatViewController
    private func presentChat(host: String,
                             apiKey: String,
                             workSpaceId: String,
                             appId: String,
                             img: String,
                             payMode: String) {
        let chatView = ChatViewController()
        chatView.dialogMode = selectedDialogMode
        chatView.updateParam(url: host,
                             apiKey: apiKey,
                             workSpaceId: workSpaceId,
                             appId: appId,
                             image_url: img,
                             payMode: payMode)
        print("==========>>>>>>>>> start dialog (payMode=\(payMode))")
        self.present(chatView, animated: true)
    }

    // MARK: - Alert

    private func showAlertMessage(_ message: String) {
        let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default) { [weak self] _ in
            self?.messageAlert = nil
        })
        if let current = messageAlert {
            current.dismiss(animated: true) { [weak self] in
                guard let self = self else { return }
                self.present(alert, animated: true)
                self.messageAlert = alert
            }
        } else {
            present(alert, animated: true)
            messageAlert = alert
        }
    }

    // MARK: - Helpers

    private func getTextOrPlaceholder(from textField: UITextField) -> String {
        if let text = textField.text, !text.isEmpty {
            return text
        } else {
            return textField.placeholder ?? ""
        }
    }
}

// MARK: - UITextFieldDelegate
extension FirstViewController: UITextFieldDelegate {

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        let fields = [workspaceIdField, appIdField, apiKeyField, serverUrlField, imageUrlField]
        if let index = fields.firstIndex(of: textField), index < fields.count - 1 {
            fields[index + 1].becomeFirstResponder()
        } else {
            textField.resignFirstResponder()
        }
        return true
    }
}

// MARK: - Permission Handling
extension FirstViewController {

    func checkCameraPermission() -> AVAuthorizationStatus {
        return AVCaptureDevice.authorizationStatus(for: .video)
    }

    func checkMicrophonePermission() -> AVAuthorizationStatus {
        return AVCaptureDevice.authorizationStatus(for: .audio)
    }

    func requestCameraPermission(completion: @escaping (Bool) -> Void) {
        AVCaptureDevice.requestAccess(for: .video) { granted in
            DispatchQueue.main.async {
                completion(granted)
            }
        }
    }

    func requestMicrophonePermission(completion: @escaping (Bool) -> Void) {
        AVCaptureDevice.requestAccess(for: .audio) { granted in
            DispatchQueue.main.async {
                completion(granted)
            }
        }
    }

    func checkAndRequestPermissions() -> Bool {
        var hasCameraPermission = true
        var hasMicrophonePermission = true

        // 检查摄像头权限
        let cameraStatus = checkCameraPermission()
        switch cameraStatus {
        case .authorized:
            print("摄像头已授权")
            hasCameraPermission = true
        case .denied, .restricted:
            print("摄像头权限被拒绝")
            hasCameraPermission = false
            showAlertToSettings()
        case .notDetermined:
            requestCameraPermission { granted in
                if granted {
                    print("摄像头权限已授予")
                    hasCameraPermission = true
                } else {
                    print("用户拒绝了摄像头权限")
                    hasCameraPermission = false
                }
            }
        @unknown default:
            break
        }

        // 检查麦克风权限
        let microphoneStatus = checkMicrophonePermission()
        switch microphoneStatus {
        case .authorized:
            print("麦克风已授权")
            hasMicrophonePermission = true
        case .denied, .restricted:
            print("麦克风权限被拒绝")
            hasMicrophonePermission = false
            showAlertToSettings()
        case .notDetermined:
            requestMicrophonePermission { granted in
                if granted {
                    print("麦克风权限已授予")
                    hasMicrophonePermission = true
                } else {
                    print("用户拒绝了麦克风权限")
                    hasMicrophonePermission = false
                }
            }
        @unknown default:
            break
        }

        return hasMicrophonePermission && hasCameraPermission
    }

    func showAlertToSettings() {
        let alert = UIAlertController(
            title: "权限被拒绝",
            message: "请在设置中启用权限",
            preferredStyle: .alert
        )

        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        alert.addAction(UIAlertAction(title: "去设置", style: .default) { _ in
            if let url = URL(string: UIApplication.openSettingsURLString) {
                UIApplication.shared.open(url)
            }
        })

        if let topVC = UIApplication.shared.windows.first?.rootViewController {
            topVC.present(alert, animated: true)
        }
    }
}
