//
//  PaymentCollectionDetailsViewModel.swift
//  suixinkan
//

import Foundation
import UIKit

/// 收款详情 ViewModel，管理收款码拉取、设金额、保存二维码与语音开关。
final class PaymentCollectionDetailsViewModel {

    private(set) var loading = false
    private(set) var qrImage: UIImage?
    private(set) var scenicName = ""
    private(set) var staffId = ""
    private(set) var isVoiceBroadcastOpen = false
    private(set) var showAmountDialog = false
    private(set) var amount = ""
    private(set) var remark = ""
    private(set) var scenicId = 0
    private(set) var payPageConfig = PayPageConfig.nalatiDefault
    private(set) var brandingRefreshVersion = 0

    let merchantInfo = PaymentMerchantInfo.defaultInfo

    var onStateChange: (() -> Void)?
    var onShowMessage: ((String) -> Void)?

    private var staticPayURL = ""
    private var dynamicPayURL = ""
    private let appStore: AppStore
    private let payPageConfigCache: PayPageConfigCaching

    init(
        appStore: AppStore = .shared,
        payPageConfigCache: PayPageConfigCaching = PayPageConfigCache()
    ) {
        self.appStore = appStore
        self.payPageConfigCache = payPageConfigCache
        scenicId = appStore.session.currentScenicId
        scenicName = appStore.session.currentScenicName
        staffId = appStore.session.userId
        isVoiceBroadcastOpen = appStore.payment.isOpenReceiveVoice
        if PayPageBrandingPolicy.isNalati(scenicId: scenicId) {
            payPageConfig = payPageConfigCache.config(scenicId: scenicId) ?? .nalatiDefault
        }
    }

    var hasPayCode: Bool {
        qrImage != nil && !staticPayURL.isEmpty
    }

    var displayScenicName: String {
        scenicName.isEmpty ? "暂无景区" : scenicName
    }

    var usesNalatiBranding: Bool {
        PayPageBrandingPolicy.isNalati(scenicId: scenicId)
    }

    var displayPhotographerName: String {
        PaymentAccountDisplayFormatter.photographerName(
            userName: appStore.session.userName,
            realName: appStore.session.realName
        )
    }

    var displayStoreNames: String {
        let names = appStore.permissions.rolePermissionList().flatMap(\.store).map(\.name)
        return PaymentAccountDisplayFormatter.storeNames(names)
    }

    func refreshLocalState() {
        scenicId = appStore.session.currentScenicId
        scenicName = appStore.session.currentScenicName
        staffId = appStore.session.userId
        isVoiceBroadcastOpen = appStore.payment.isOpenReceiveVoice
        if usesNalatiBranding {
            payPageConfig = payPageConfigCache.config(scenicId: scenicId) ?? .nalatiDefault
        } else {
            payPageConfig = .nalatiDefault
        }
        notifyStateChange()
    }

    func loadPayCode(api: PaymentAPI) async {
        guard !loading else { return }
        refreshLocalState()
        loading = true
        notifyStateChange()
        defer {
            loading = false
            notifyStateChange()
        }

        let scenicId = self.scenicId
        guard scenicId > 0 else {
            clearPayCode()
            return
        }

        do {
            let response = try await api.payCode(scenicId: scenicId)
            staticPayURL = response.staticPayURL
            dynamicPayURL = response.dynamicPayURL
            qrImage = QRCodeGenerator.generateStyledQRCode(content: staticPayURL)
        } catch {
            clearPayCode()
        }
    }

    func loadPayPageConfig(api: PaymentAPI) async {
        let requestedScenicId = appStore.session.currentScenicId
        guard PayPageBrandingPolicy.isNalati(scenicId: requestedScenicId) else { return }

        do {
            let response = try await api.payPageConfig(scenicId: requestedScenicId)
            guard appStore.session.currentScenicId == requestedScenicId else { return }
            let resolved = payPageConfig.merging(response)
            payPageConfigCache.save(resolved, scenicId: requestedScenicId)
            payPageConfig = resolved
            brandingRefreshVersion += 1
            notifyStateChange()
        } catch {
            // 品牌配置失败时保留缓存或随包默认值，不影响收款码与页面交互。
        }
    }

    func refresh(api: PaymentAPI) async {
        async let payCode: Void = loadPayCode(api: api)
        async let pageConfig: Void = loadPayPageConfig(api: api)
        _ = await (payCode, pageConfig)
    }

    func showSetAmountDialog() {
        guard !staticPayURL.isEmpty else {
            onShowMessage?("请先获取收款码")
            return
        }
        amount = ""
        remark = ""
        showAmountDialog = true
        notifyStateChange()
    }

    func hideAmountDialog() {
        showAmountDialog = false
        amount = ""
        remark = ""
        notifyStateChange()
    }

    func updateAmount(_ value: String) {
        guard value.isEmpty || value.matches(PaymentAmountValidator.inputPattern) else { return }
        amount = value
        notifyStateChange()
    }

    func updateRemark(_ value: String) {
        guard value.count <= 200 else { return }
        remark = value
        notifyStateChange()
    }

    func confirmAmount() {
        if let message = PaymentAmountValidator.validationMessage(for: amount) {
            onShowMessage?(message)
            return
        }
        guard !dynamicPayURL.isEmpty else {
            onShowMessage?("请先获取收款码")
            return
        }

        let dynamicURL = dynamicPayURL + "&amount=\(amount)&remark=\(remark)"
        qrImage = QRCodeGenerator.generateStyledQRCode(content: dynamicURL)
        showAmountDialog = false
        onShowMessage?("金额设置成功，二维码已更新")
        notifyStateChange()
    }

    func saveQRCode() async {
        guard qrImage != nil else {
            onShowMessage?("请先获取收款码")
            return
        }
        let success = await PhotoLibrarySaver.saveImage(qrImage!)
        onShowMessage?(success ? "保存成功" : "保存失败")
    }

    func toggleReceiveVoice() {
        isVoiceBroadcastOpen.toggle()
        appStore.payment.isOpenReceiveVoice = isVoiceBroadcastOpen
        notifyStateChange()
    }

    private func clearPayCode() {
        staticPayURL = ""
        dynamicPayURL = ""
        qrImage = nil
    }

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

/// 收款金额校验，对齐 Android `PaymentCollectionDetailsViewModel.confirmAmount`。
enum PaymentAmountValidator {
    static let inputPattern = #"^\d*(\.\d{0,2})?$"#
    private static let confirmPattern = #"^\d+(\.\d{1,2})?$"#

    static func validationMessage(for amount: String) -> String? {
        if amount.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            return "请输入收款金额"
        }
        guard let value = Double(amount), value > 0 else {
            return "请输入有效的收款金额"
        }
        if !amount.matches(confirmPattern) {
            return "金额最多支持两位小数"
        }
        return nil
    }
}

private extension String {
    func matches(_ pattern: String) -> Bool {
        range(of: pattern, options: .regularExpression) != nil
    }
}
