//
//  WithdrawalSettingsViewModel.swift
//  suixinkan
//

import Foundation

/// 提现设置 ViewModel，管理银行卡绑定两步表单与提交状态。
final class WithdrawalSettingsViewModel {
    private(set) var currentStep = 1
    private(set) var holderName = ""
    private(set) var bankNo = ""
    private(set) var bankCardFrontURL = ""
    private(set) var bankCardBackURL = ""
    private(set) var bankName = ""
    private(set) var provinceCode = ""
    private(set) var provinceName = ""
    private(set) var cityCode = ""
    private(set) var cityName = ""
    private(set) var branchName = ""
    private(set) var verificationCode = ""
    private(set) var isAgree = false
    private(set) var banks: [String] = []
    private(set) var areas: [AreasResponse] = []
    private(set) var loading = false
    private(set) var sendingCode = false
    private(set) var submitting = false

    private(set) var pendingFrontImageData: Data?
    private(set) var pendingBackImageData: Data?
    private var pendingFrontFileName: String?
    private var pendingBackFileName: String?

    var onStateChange: (() -> Void)?

    var canGoNextStep: Bool {
        currentStep == 1
            && !holderName.trimmed.isEmpty
            && (12 ... 25).contains(bankNo.filter(\.isNumber).count)
            && !bankCardFrontURL.isEmpty
            && !bankCardBackURL.isEmpty
            && isAgree
    }

    var canSubmit: Bool {
        currentStep == 2
            && !holderName.trimmed.isEmpty
            && (12 ... 25).contains(bankNo.filter(\.isNumber).count)
            && !bankName.trimmed.isEmpty
            && !provinceCode.isEmpty
            && !cityCode.isEmpty
            && !branchName.trimmed.isEmpty
            && !verificationCode.trimmed.isEmpty
            && isAgree
            && !submitting
    }

    func updateHolderName(_ value: String) {
        holderName = value
        notifyStateChange()
    }

    func updateBankNo(_ value: String) {
        bankNo = value
        notifyStateChange()
    }

    func updateBankName(_ value: String) {
        bankName = value
        notifyStateChange()
    }

    func updateBranchName(_ value: String) {
        branchName = value
        notifyStateChange()
    }

    func updateVerificationCode(_ value: String) {
        verificationCode = value
        notifyStateChange()
    }

    func updateAgree(_ value: Bool) {
        isAgree = value
        notifyStateChange()
    }

    func selectProvince(_ area: AreasResponse) {
        provinceCode = area.code
        provinceName = area.name
        cityCode = ""
        cityName = ""
        notifyStateChange()
    }

    func selectCity(_ area: AreasResponse) {
        cityCode = area.code
        cityName = area.name
        notifyStateChange()
    }

    func goNextStep() {
        guard canGoNextStep else { return }
        currentStep = 2
        notifyStateChange()
    }

    func prepareBankCardImage(data: Data, side: BankCardImageSide) throws {
        let processed = try BankCardImageProcessor.process(data: data, side: side)
        switch side {
        case .front:
            pendingFrontImageData = processed.data
            pendingFrontFileName = processed.fileName
            bankCardFrontURL = "pending"
        case .back:
            pendingBackImageData = processed.data
            pendingBackFileName = processed.fileName
            bankCardBackURL = "pending"
        }
        notifyStateChange()
    }

    func load(api: ProfileAPI) async throws {
        guard !loading else { return }
        loading = true
        notifyStateChange()
        defer {
            loading = false
            notifyStateChange()
        }
        async let bankList = api.bankList()
        async let areaList = api.areas()
        let result = try await (bankList, areaList)
        banks = result.0.banks
        areas = result.1
        notifyStateChange()
    }

    func sendCode(api: ProfileAPI) async throws {
        guard !sendingCode else { return }
        sendingCode = true
        notifyStateChange()
        defer {
            sendingCode = false
            notifyStateChange()
        }
        try await api.bankCardSmsVerifyCode()
    }

    func submit(api: ProfileAPI, uploader: any OSSUploadServing, scenicId: Int) async throws {
        guard canSubmit else {
            throw WithdrawalValidationError.message("请完善银行卡信息")
        }
        submitting = true
        notifyStateChange()
        defer {
            submitting = false
            notifyStateChange()
        }
        try await uploadPendingImages(uploader: uploader, scenicId: scenicId)
        let request = UpdateBankInfoRequest(
            realName: holderName.trimmed,
            cardNumber: bankNo.filter(\.isNumber),
            bankName: bankName.trimmed,
            branchName: branchName.trimmed,
            frontUrl: bankCardFrontURL,
            backUrl: bankCardBackURL,
            provinceCode: provinceCode,
            cityCode: cityCode,
            smsVerifyCode: verificationCode.trimmed
        )
        try await api.updateBankCard(request)
    }

    var provinceOptions: [AreasResponse] { areas }

    var cityOptions: [AreasResponse] {
        areas.first { $0.code == provinceCode || $0.name == provinceName }?.children ?? []
    }

    private func uploadPendingImages(uploader: any OSSUploadServing, scenicId: Int) async throws {
        if let pendingFrontImageData {
            bankCardFrontURL = try await uploader.uploadBankCardImage(
                data: pendingFrontImageData,
                fileName: pendingFrontFileName ?? "bank_card_front.jpg",
                scenicId: scenicId
            ) { _ in }
            self.pendingFrontImageData = nil
        }
        if let pendingBackImageData {
            bankCardBackURL = try await uploader.uploadBankCardImage(
                data: pendingBackImageData,
                fileName: pendingBackFileName ?? "bank_card_back.jpg",
                scenicId: scenicId
            ) { _ in }
            self.pendingBackImageData = nil
        }
    }

    private func notifyStateChange() {
        onStateChange?()
    }
}

enum WithdrawalValidationError: LocalizedError, Equatable {
    case message(String)

    var errorDescription: String? {
        switch self {
        case .message(let message): message
        }
    }
}

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