//
//  PilotCertificationViewModel.swift
//  suixinkan
//
//  Created by Codex on 2026/6/25.
//

import Foundation
import Combine

@MainActor
/// 飞手认证实名认证读取协议，便于 ViewModel 单测替换。
protocol PilotRealNameServing {
    func realNameInfo() async throws -> RealNameInfoResponse
}

extension ProfileAPI: PilotRealNameServing {}

@MainActor
/// 飞手认证 ViewModel，管理审核状态、表单、验证码、证件图上传和提交。
final class PilotCertificationViewModel: ObservableObject {
    @Published private(set) var flyer: FlyerDetailResponse?
    @Published private(set) var realNameInfo: RealNameInfo?
    @Published var name = ""
    @Published var certType: PilotCertType = .caac
    @Published var certNo = ""
    @Published var certImageUrl = ""
    @Published var startDate = Date()
    @Published var endDate = Calendar.current.date(byAdding: .year, value: 1, to: Date()) ?? Date()
    @Published var droneModel = ""
    @Published var droneSerialNo = ""
    @Published var phone = ""
    @Published var verifyCode = ""
    @Published private(set) var pendingCertificateImageData: Data?
    @Published private(set) var pendingCertificateFileName: String?
    @Published private(set) var uploadProgress: Int?
    @Published private(set) var loading = false
    @Published private(set) var sendingCode = false
    @Published private(set) var submitting = false
    @Published private(set) var countdown = 0
    @Published var statusMessage: String?

    /// 加载实名状态和飞手认证详情，单通道失败不清空另一通道数据。
    func load(api: any PilotCertificationServing, realNameAPI: any PilotRealNameServing) async {
        guard !loading else { return }
        loading = true
        defer { loading = false }

        async let realNameTask = realNameAPI.realNameInfo()
        async let flyerTask = api.flyerDetail()
        var messages: [String] = []

        do {
            let response = try await realNameTask
            realNameInfo = response.realNameInfo
        } catch {
            messages.append(error.localizedDescription)
        }

        do {
            apply(try await flyerTask)
        } catch {
            messages.append(error.localizedDescription)
        }

        statusMessage = messages.isEmpty ? nil : messages.joined(separator: "\n")
    }

    /// 选择待上传证件图。
    func prepareCertificateImage(data: Data, fileName: String) {
        pendingCertificateImageData = data
        pendingCertificateFileName = fileName.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
            ? "pilot_cert_\(Int(Date().timeIntervalSince1970)).jpg"
            : fileName
        certImageUrl = ""
        uploadProgress = nil
    }

    /// 发送验证码，成功后进入 60 秒倒计时。
    func sendCode(api: any PilotCertificationServing) async throws {
        guard canSendCode else {
            throw PilotCertificationValidationError.message("请输入有效的手机号码")
        }
        sendingCode = true
        defer { sendingCode = false }

        try await api.flyerSendCode(phone: AppFormValidator.normalizedPhoneNumber(phone))
        countdown = 60
        statusMessage = "验证码已发送"
    }

    /// 倒计时递减，由页面定时器驱动。
    func tickCountdown() {
        if countdown > 0 {
            countdown -= 1
        }
    }

    /// 提交飞手认证，必要时先上传证件图。
    func submit(api: any PilotCertificationServing, uploader: any OSSUploadServing, scenicId: Int?) async throws {
        if let validationMessage {
            throw PilotCertificationValidationError.message(validationMessage)
        }

        submitting = true
        defer { submitting = false }

        try await uploadPendingCertificateImage(uploader: uploader, scenicId: scenicId)
        if auditStatus == 3, flyerId > 0 {
            try await api.flyerEdit(makeEditRequest())
            statusMessage = "修改已提交"
        } else {
            try await api.flyerApply(makeApplyRequest())
            statusMessage = "认证申请已提交"
        }
        await load(api: api, realNameAPI: PilotEmptyRealNameServing(info: realNameInfo))
    }

    /// 审核状态编码。
    var auditStatus: Int {
        flyer?.status ?? 0
    }

    /// 飞手认证记录 ID。
    var flyerId: Int {
        flyer?.id ?? 0
    }

    /// 审核通过后表单只读。
    var isReadOnly: Bool {
        auditStatus == 2
    }

    /// 实名是否已通过。
    var isRealNameVerified: Bool {
        realNameInfo?.verified == true || flyer?.realnameStatus == 2
    }

    /// 是否允许发送验证码。
    var canSendCode: Bool {
        !sendingCode && countdown == 0 && (auditStatus == 0 || auditStatus == 3) && AppFormValidator.isValidMainlandPhoneNumber(phone)
    }

    /// 当前表单校验错误。
    var validationMessage: String? {
        if isReadOnly { return "认证已通过，无需重复提交" }
        if auditStatus != 0 && auditStatus != 3 { return "认证审核中，请等待审核结果" }
        if name.trimmedForPilot.isEmpty { return "请输入飞手昵称" }
        if certNo.trimmedForPilot.isEmpty { return "请输入证件号码" }
        if certImageUrl.trimmedForPilot.isEmpty && pendingCertificateImageData == nil { return "请选择证件图片" }
        if endDate < startDate { return "截至日期不能早于起始日期" }
        if droneModel.trimmedForPilot.isEmpty { return "请输入无人机型号" }
        if droneSerialNo.trimmedForPilot.isEmpty { return "请输入无人机序列号" }
        if phone.trimmedForPilot.isEmpty { return "请输入手机号码" }
        if !AppFormValidator.isValidMainlandPhoneNumber(phone) { return "请输入有效的手机号码" }
        if verifyCode.trimmedForPilot.isEmpty { return "请输入验证码" }
        return nil
    }

    /// 审核状态展示文本。
    var auditStatusText: String {
        flyer?.statusName.trimmedForPilot.nonEmptyForPilot ?? Self.statusName(for: auditStatus)
    }

    /// 最近审核日志。
    var latestAuditLog: FlyerCertificationLogItem? {
        flyer?.certificationLogs.last { $0.action == 2 || $0.action == 3 }
    }

    private func apply(_ flyer: FlyerDetailResponse) {
        self.flyer = flyer
        name = flyer.name
        certType = PilotCertType(rawValue: flyer.certificateType) ?? .caac
        certNo = flyer.certificateNo
        certImageUrl = flyer.certificateImage
        startDate = Self.date(from: flyer.certificateStartDate) ?? startDate
        endDate = Self.date(from: flyer.certificateEndDate) ?? endDate
        droneModel = flyer.droneModel
        droneSerialNo = flyer.droneSn
        phone = flyer.contactPhone
        pendingCertificateImageData = nil
        pendingCertificateFileName = nil
        uploadProgress = nil
    }

    private func uploadPendingCertificateImage(uploader: any OSSUploadServing, scenicId: Int?) async throws {
        guard let data = pendingCertificateImageData else { return }
        guard let scenicId, scenicId > 0 else {
            throw PilotCertificationValidationError.message("请先选择景区")
        }
        uploadProgress = 1
        defer { uploadProgress = nil }
        certImageUrl = try await uploader.uploadPilotCertificateImage(
            data: data,
            fileName: pendingCertificateFileName ?? "pilot_cert_\(Int(Date().timeIntervalSince1970)).jpg",
            scenicId: scenicId
        ) { [weak self] progress in
            Task { @MainActor in
                self?.uploadProgress = progress
            }
        }
        pendingCertificateImageData = nil
        pendingCertificateFileName = nil
    }

    private func makeApplyRequest() -> FlyerApplyRequest {
        FlyerApplyRequest(
            name: name.trimmedForPilot,
            realnameStatus: isRealNameVerified ? 1 : 2,
            certificateType: certType.rawValue,
            certificateNo: certNo.trimmedForPilot,
            certificateStartDate: Self.dateFormatter.string(from: startDate),
            certificateEndDate: Self.dateFormatter.string(from: endDate),
            certificateImage: certImageUrl.trimmedForPilot,
            droneModel: droneModel.trimmedForPilot,
            droneSn: droneSerialNo.trimmedForPilot,
            contactPhone: AppFormValidator.normalizedPhoneNumber(phone),
            code: verifyCode.trimmedForPilot
        )
    }

    private func makeEditRequest() -> FlyerEditRequest {
        let apply = makeApplyRequest()
        return FlyerEditRequest(
            id: flyerId,
            name: apply.name,
            realnameStatus: apply.realnameStatus,
            certificateType: apply.certificateType,
            certificateNo: apply.certificateNo,
            certificateStartDate: apply.certificateStartDate,
            certificateEndDate: apply.certificateEndDate,
            certificateImage: apply.certificateImage,
            droneModel: apply.droneModel,
            droneSn: apply.droneSn,
            contactPhone: apply.contactPhone,
            code: apply.code
        )
    }

    private static func statusName(for status: Int) -> String {
        switch status {
        case 1: "审核中"
        case 2: "已通过"
        case 3: "审核失败"
        default: "未提交"
        }
    }

    private static let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .gregorian)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter
    }()

    private static func date(from value: String) -> Date? {
        let text = String(value.prefix(10))
        guard !text.isEmpty else { return nil }
        return dateFormatter.date(from: text)
    }
}

private struct PilotEmptyRealNameServing: PilotRealNameServing {
    let info: RealNameInfo?

    func realNameInfo() async throws -> RealNameInfoResponse {
        RealNameInfoResponse(realNameInfo: info)
    }
}

private extension String {
    var trimmedForPilot: String {
        trimmingCharacters(in: .whitespacesAndNewlines)
    }

    var nonEmptyForPilot: String? {
        let value = trimmedForPilot
        return value.isEmpty ? nil : value
    }
}
