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

import Foundation
import Combine
import SwiftUI

@MainActor
/// 景区结算申请 ViewModel，管理可申请景区、多选、金额备注和提交。
final class ScenicSettlementViewModel: ObservableObject {
    @Published var existingScenics: [BusinessScope] = []
    @Published var options: [ScenicSettlementOption] = []
    @Published var amountText = ""
    @Published var remarkText = ""
    @Published var isLoading = false
    @Published var isSubmitting = false
    @Published var loadFailed = false
    @Published var loadFailureReason: String?
    @Published var message: String?

    @Published private var selectedIds = Set<Int>()

    /// 已选择景区数量。
    var selectedCount: Int {
        selectedIds.count
    }

    /// 当前选择的景区 ID，供测试和提交使用。
    var selectedScenicIds: Set<Int> {
        selectedIds
    }

    /// 金额校验状态。
    var amountValidation: ScenicSettlementAmountValidation {
        let trimmed = amountText.trimmingCharacters(in: .whitespacesAndNewlines)
        if trimmed.isEmpty { return .empty }
        guard trimmed.range(of: #"^\d+(\.\d{1,2})?$"#, options: .regularExpression) != nil else {
            return .invalidFormat
        }
        guard let decimal = Decimal(string: trimmed), decimal > 0 else {
            return .notPositive
        }
        return .valid
    }

    /// 是否允许提交结算申请。
    var canSubmit: Bool {
        !isSubmitting && !selectedIds.isEmpty && amountValidation == .valid
    }

    /// 加载已开通景区和可申请结算景区。
    func load(api: any ScenicPermissionServing, existingScenics: [BusinessScope]) async {
        isLoading = true
        loadFailed = false
        loadFailureReason = nil
        self.existingScenics = existingScenics
        defer { isLoading = false }

        do {
            let all = try await api.scenicListAll().list
            let existingIds = Set(existingScenics.map(\.id))
            options = all
                .filter { !existingIds.contains($0.id) }
                .map { ScenicSettlementOption(id: $0.id, name: $0.name, selected: selectedIds.contains($0.id)) }
        } catch {
            options = []
            selectedIds.removeAll()
            loadFailed = true
            loadFailureReason = error.localizedDescription
            message = "可申请景区加载失败，请重试"
        }
    }

    /// 切换一个景区的结算申请选择状态。
    func toggleScenic(id: Int) {
        guard let index = options.firstIndex(where: { $0.id == id }) else { return }
        options[index].selected.toggle()
        if options[index].selected {
            selectedIds.insert(id)
        } else {
            selectedIds.remove(id)
        }
    }

    /// 提交结算申请，多景区按 ID 升序逐条提交。
    func submit(api: any ScenicSettlementServing) async -> Bool {
        guard !isSubmitting else { return false }
        guard canSubmit else {
            message = validationMessage
            return false
        }

        isSubmitting = true
        defer { isSubmitting = false }

        let amount = normalizedAmount
        let remark = remarkText.trimmingCharacters(in: .whitespacesAndNewlines)

        do {
            for scenicId in selectedIds.sorted() {
                try await api.scenicSettlementSubmit(
                    ScenicSettlementSubmitRequest(
                        scenicId: scenicId,
                        applyAmount: amount,
                        applyRemark: remark
                    )
                )
            }
            selectedIds.removeAll()
            options = options.map { option in
                ScenicSettlementOption(id: option.id, name: option.name, selected: false)
            }
            amountText = ""
            remarkText = ""
            message = "提交成功，等待审核"
            return true
        } catch {
            message = error.localizedDescription
            return false
        }
    }

    private var normalizedAmount: String {
        let decimal = Decimal(string: amountText.trimmingCharacters(in: .whitespacesAndNewlines)) ?? 0
        return String(format: "%.2f", NSDecimalNumber(decimal: decimal).doubleValue)
    }

    private var validationMessage: String {
        if selectedIds.isEmpty { return "请先选择景区" }
        switch amountValidation {
        case .empty:
            return "请填写结算金额"
        case .invalidFormat:
            return "金额格式错误，最多支持两位小数"
        case .notPositive:
            return "金额需大于 0"
        case .valid:
            return ""
        }
    }
}

/// 景区结算金额校验结果。
enum ScenicSettlementAmountValidation: Equatable {
    case empty
    case invalidFormat
    case notPositive
    case valid

    /// 对应的状态提示文案。
    var badgeText: String {
        switch self {
        case .empty: "待填写金额"
        case .invalidFormat: "金额格式错误"
        case .notPositive: "金额需大于 0"
        case .valid: "金额有效"
        }
    }

    /// 对应的状态颜色。
    var badgeColor: Color {
        switch self {
        case .empty, .notPositive:
            return AppDesign.warning
        case .invalidFormat:
            return Color(hex: 0xDC2626)
        case .valid:
            return AppDesign.success
        }
    }
}

@MainActor
/// 景区结算审核 ViewModel，聚合景区申请和权限申请审核记录。
final class ScenicSettlementReviewViewModel: ObservableObject {
    @Published var scenicApplications: [ScenicApplicationPendingResponse] = []
    @Published var roleApplications: [RoleApplyPendingResponse] = []
    private var isLoading = false
    @Published var message: String?
    @Published var loadFailedAll = false
    @Published var scenicLoadFailed = false
    @Published var roleLoadFailed = false

    /// 待审核记录数量。
    var pendingCount: Int {
        scenicApplications.filter { $0.status == 1 }.count + roleApplications.filter { $0.status == 1 }.count
    }

    /// 加载审核记录，单通道失败时保留另一通道数据。
    func load(api: any ScenicPermissionServing) async {
        isLoading = true
        loadFailedAll = false
        scenicLoadFailed = false
        roleLoadFailed = false
        message = nil
        defer { isLoading = false }

        var errors: [String] = []
        var scenicLoaded = false
        var roleLoaded = false

        do {
            scenicApplications = try await api.scenicApplicationPendingAll().items
            scenicLoaded = true
        } catch {
            scenicApplications = []
            scenicLoadFailed = true
            errors.append("景区申请记录加载失败")
        }

        do {
            roleApplications = try await api.roleApplyAll()
            roleLoaded = true
        } catch {
            roleApplications = []
            roleLoadFailed = true
            errors.append("权限申请记录加载失败")
        }

        loadFailedAll = !scenicLoaded && !roleLoaded
        if !errors.isEmpty {
            message = errors.joined(separator: "；")
        }
    }

    /// 审核状态文案。
    func statusText(_ status: Int, fallback: String = "") -> String {
        let trimmed = fallback.trimmingCharacters(in: .whitespacesAndNewlines)
        if !trimmed.isEmpty { return trimmed }
        switch status {
        case 1: return "待审核"
        case 2: return "已通过"
        case 3: return "已驳回"
        case 9: return "已取消"
        default: return "未知"
        }
    }

    /// 审核状态图标。
    func statusIcon(_ status: Int) -> String {
        switch status {
        case 2: return "checkmark.circle.fill"
        case 3: return "xmark.octagon.fill"
        case 1: return "clock.badge.exclamationmark.fill"
        default: return "questionmark.circle.fill"
        }
    }

    /// 审核状态颜色。
    func statusColor(_ status: Int) -> Color {
        switch status {
        case 2: return AppDesign.success
        case 3: return Color(hex: 0xDC2626)
        case 1: return AppDesign.warning
        default: return AppDesign.textSecondary
        }
    }
}
