//
//  OrderListViewModel.swift
//  suixinkan
//

import Foundation

struct MultiVerifyParseData: Equatable {
    let orderNumber: String
    let userId: Int
    let time: Int64
    let checkSum: String
}

struct OrderSourcePerson: Equatable {
    let key: String
    let name: String
    let phone: String
}

struct OrderSourceLead: Equatable {
    let key: String
    let userPhone: String
    let remark: String
    let images: [String]
}

enum OrderSourceMapping {

    /// 将 API 带客单实体映射为订单来源选择项，对齐 Android `toOrderSourceLead()`。
    static func lead(from entity: ReferralOrderEntity) -> OrderSourceLead {
        let orderNo = entity.displayReferralOrderNo
        let remark: String
        if !entity.remark.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            remark = entity.remark
        } else if !entity.statusLabel.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            remark = entity.statusLabel
        } else {
            remark = "带客单 \(orderNo)"
        }
        return OrderSourceLead(
            key: orderNo,
            userPhone: entity.userMobile,
            remark: remark,
            images: entity.images
        )
    }

    /// 将已绑定带客单实体映射为订单来源选择项，对齐 Android `toOrderSourceSelection()`。
    static func selection(from referral: BoundReferralOrderEntity) -> OrderSourceSelection? {
        let referralNo = referral.orderNo.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !referralNo.isEmpty else { return nil }

        let personName = referral.displaySalerName.isEmpty ? "—" : referral.displaySalerName
        let person = OrderSourcePerson(
            key: referral.saleUserId > 0 ? String(referral.saleUserId) : "",
            name: personName,
            phone: referral.salerPhone
        )
        let remark: String
        if !referral.remark.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            remark = referral.remark
        } else if !referral.displayText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            remark = referral.displayText
        } else {
            remark = "带客单号 \(referralNo)"
        }
        let lead = OrderSourceLead(
            key: referralNo,
            userPhone: referral.userMobile,
            remark: remark,
            images: []
        )
        return OrderSourceSelection(person: person, lead: lead)
    }
}

struct OrderSourceSelection: Equatable {
    let person: OrderSourcePerson
    let lead: OrderSourceLead
}

/// 摄影师/景区管理员订单列表 ViewModel，对齐 Android `OrderListViewModel`。
final class OrderListViewModel {

    private(set) var orderList: [OrderEntity] = []
    private(set) var searchText = ""
    private(set) var filterLabel = "全部"
    private(set) var tabIndex = 0
    private(set) var rTabIndex = 0
    private(set) var startTime: Date?
    private(set) var endTime: Date?
    private(set) var isRefreshing = false
    private(set) var canLoadMore = false
    private(set) var isLoadingMore = false

    private(set) var multiVerifyPendingData: MultiVerifyParseData?
    private(set) var multiVerifyScenicSpotList: [MultiTravelScenicSpotEntity] = []
    private(set) var selectedMultiVerifySpot: MultiTravelScenicSpotEntity?
    private(set) var signInResponse: OrderSignInResponse?
    private(set) var writeOffResponse: WriteOffOrderResponse?

    private(set) var orderSourcePeople: [OrderSourcePerson] = []
    private(set) var orderSourceLeads: [String: [OrderSourceLead]] = [:]
    private(set) var orderSourceSelections: [String: OrderSourceSelection] = [:]
    private(set) var loadingOrderSourceLeadsFor: String?
    private(set) var isLoadingOrderSourcePeople = false

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

    private var currentPage = 1
    private var totalCount = 0

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

    var isScenicAdminReadOnly: Bool {
        AppStore.shared.session.currentAppRole == .scenicAdmin
    }

    var listAPIPath: String {
        isScenicAdminReadOnly
            ? "/api/app/scenic-admin/order/list"
            : "/api/yf-handset-app/photog/order/listv2"
    }

    func refreshOrderList(api: OrderAPI) async {
        currentPage = 1
        isRefreshing = true
        isLoadingMore = false
        orderList = []
        notifyStateChange()
        await loadOrderList(api: api, append: false)
    }

    func loadMore(api: OrderAPI) async {
        guard !isLoadingMore, !isRefreshing else { return }
        guard orderList.count < totalCount else { return }
        isLoadingMore = true
        currentPage += 1
        notifyStateChange()
        await loadOrderList(api: api, append: true)
    }

    func shouldLoadMore(at index: Int) -> Bool {
        guard canLoadMore, !isRefreshing, !isLoadingMore else { return false }
        return index >= max(0, orderList.count - 3)
    }

    func onSearchTextChange(_ text: String) {
        searchText = text
        notifyStateChange()
    }

    func onFilterChange(orderStatus: Int, isRefined: Int) {
        tabIndex = orderStatus
        rTabIndex = isRefined
        filterLabel = PhotographerOrderFilter.from(tabIndex: orderStatus, rTabIndex: isRefined).label
        notifyStateChange()
    }

    func onDateRangeSelected(start: Date?, end: Date?) {
        startTime = start
        endTime = end
        notifyStateChange()
    }

    func cancelOrder(orderNumber: String, api: OrderAPI) async {
        guard !abortIfScenicAdminReadOnlyMutation() else { return }
        do {
            try await api.cancelOrder(CancelRequest(orderNumber: orderNumber))
            onShowMessage?("取消成功")
            await refreshOrderList(api: api)
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    func refundOrder(_ request: OrderRefundRequest, api: OrderAPI) async {
        guard !abortIfScenicAdminReadOnlyMutation() else { return }
        do {
            try await api.refundOrder(request)
            onShowMessage?("退款成功")
            await refreshOrderList(api: api)
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    func sendGift(orderNumber: String, photoNum: Int, videoNum: Int, api: OrderAPI) async {
        guard !abortIfScenicAdminReadOnlyMutation() else { return }
        do {
            try await api.giftRetouch(SendGiftRequest(orderNumber: orderNumber, photoNum: photoNum, videoNum: videoNum))
            onShowMessage?("赠送成功")
            await refreshOrderList(api: api)
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    func updateRefined(orderNumber: String, isRefined: Int, api: OrderAPI) async {
        guard !abortIfScenicAdminReadOnlyMutation() else { return }
        do {
            try await api.updateRefined(orderNumber: orderNumber, isRefined: isRefined)
            await refreshOrderList(api: api)
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    func processScanResult(_ scanResult: String, api: OrderAPI) async {
        if scanResult.isEmpty {
            onShowMessage?("请扫描正确的二维码")
            return
        }
        guard !abortIfScenicAdminReadOnlyMutation() else { return }

        if let parsed = QRCodeScanResult.parse(scanResult) {
            switch parsed.method {
            case "multi_verify":
                guard !parsed.orderNumber.isEmpty, parsed.userId > 0, parsed.timeLong > 0, !parsed.checkSum.isEmpty else {
                    onShowMessage?("请扫描正确的多点位核销码")
                    return
                }
                multiVerifyPendingData = MultiVerifyParseData(
                    orderNumber: parsed.orderNumber,
                    userId: parsed.userId,
                    time: parsed.timeLong,
                    checkSum: parsed.checkSum
                )
                notifyStateChange()
                return
            case SaleUserQrParser.methodSaleUserBind:
                if let saleUserId = SaleUserQrParser.parseSaleUserId(scanResult), saleUserId > 0 {
                    onNavigateBindAcquirer?(saleUserId)
                } else {
                    onShowMessage?("请扫描正确的获客员二维码")
                }
                return
            case "order_verify":
                await performOrderVerify(jsonBody: parsed.rawJSON, api: api)
                return
            case "check_in", "":
                await performCheckIn(scanResult: scanResult, api: api)
                return
            default:
                break
            }
        }

        await performCheckIn(scanResult: scanResult, api: api)
    }

    func fetchScenicSpotsAndShowSheet(lat: Double, lng: Double, api: OrderAPI) async {
        guard let data = multiVerifyPendingData else { return }
        do {
            let response = try await api.multiTravelScenicSpotList(
                orderNumber: data.orderNumber,
                lat: lat,
                lng: lng
            )
            multiVerifyScenicSpotList = response.entityList
            selectedMultiVerifySpot = multiVerifyScenicSpotList.first
            notifyStateChange()
            if multiVerifyScenicSpotList.isEmpty {
                onShowMessage?("暂无可核销的打卡点")
                clearMultiVerifyPending()
            }
        } catch {
            onShowMessage?(error.localizedDescription)
            clearMultiVerifyPending()
        }
    }

    func onMultiVerifySpotSelected(_ spot: MultiTravelScenicSpotEntity) {
        selectedMultiVerifySpot = spot
        notifyStateChange()
    }

    func onMultiVerifyConfirm(api: OrderAPI) async {
        guard !abortIfScenicAdminReadOnlyMutation() else { return }
        guard let data = multiVerifyPendingData, let spot = selectedMultiVerifySpot else {
            onShowMessage?("请选择一个打卡点")
            return
        }
        do {
            let response = try await api.multiTravelOrderVerify(
                MultiTravelOrderVerifyRequest(
                    orderNumber: data.orderNumber,
                    userId: data.userId,
                    time: data.time,
                    checkSum: data.checkSum,
                    scenicSpotId: spot.scenicSpotId
                )
            )
            signInResponse = response
            clearMultiVerifySheet()
            notifyStateChange()
        } catch {
            onShowMessage?(error.localizedDescription)
            clearMultiVerifyPending()
        }
    }

    func clearMultiVerifySheet() {
        multiVerifyScenicSpotList = []
        selectedMultiVerifySpot = nil
        multiVerifyPendingData = nil
        notifyStateChange()
    }

    func clearMultiVerifyPending() {
        multiVerifyPendingData = nil
        notifyStateChange()
    }

    func clearSignInResponse() {
        signInResponse = nil
        notifyStateChange()
    }

    func clearWriteOffResponse() {
        writeOffResponse = nil
        notifyStateChange()
    }

    func shouldShowOrderSource(for order: OrderEntity) -> Bool {
        guard !isScenicAdminReadOnly else { return false }
        return order.orderType == OrderTypeCode.photographerFollow
            || order.orderType == OrderTypeCode.photographerFollowOfflineScan
    }

    func orderSourceSelection(for order: OrderEntity) -> OrderSourceSelection? {
        orderSourceSelection(orderNumber: order.orderNumber, referralOrder: order.referralOrder)
    }

    /// 按订单号读取当前绑定状态，供订单来源 Sheet 使用。
    func orderSourceSelection(orderNumber: String, referralOrder: BoundReferralOrderEntity? = nil) -> OrderSourceSelection? {
        if let selection = orderSourceSelections[orderNumber] { return selection }
        if let referral = referralOrder ?? orderList.first(where: { $0.orderNumber == orderNumber })?.referralOrder {
            return OrderSourceMapping.selection(from: referral)
        }
        return nil
    }

    func onOrderSourceSheetOpen(api: OrderAPI) async {
        orderSourceLeads = [:]
        guard !isLoadingOrderSourcePeople else { return }
        isLoadingOrderSourcePeople = true
        notifyStateChange()
        defer {
            isLoadingOrderSourcePeople = false
            notifyStateChange()
        }
        let storeId = AppStore.shared.session.currentStoreId
        let storeIdParam = storeId > 0 ? String(storeId) : nil
        do {
            let response = try await api.cooperativeSalers(storeId: storeIdParam)
            orderSourcePeople = response.list.map {
                OrderSourcePerson(key: String($0.saleUserId), name: $0.displayName, phone: $0.displayPhone)
            }
            notifyStateChange()
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    func loadOrderSourceLeads(person: OrderSourcePerson, api: OrderAPI) async {
        guard loadingOrderSourceLeadsFor != person.key else { return }
        loadingOrderSourceLeadsFor = person.key
        notifyStateChange()
        defer {
            loadingOrderSourceLeadsFor = nil
            notifyStateChange()
        }
        do {
            let response = try await api.referralOrders(saleUserId: person.key)
            orderSourceLeads[person.key] = response.list.map(OrderSourceMapping.lead(from:))
            notifyStateChange()
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    func bindOrderSource(orderNumber: String, selection: OrderSourceSelection, api: OrderAPI) async {
        guard !abortIfScenicAdminReadOnlyMutation() else { return }
        do {
            try await api.bindReferralOrder(orderNumber: orderNumber, referralOrderNo: selection.lead.key)
            orderSourceSelections[orderNumber] = selection
            onShowMessage?("绑定成功")
            await refreshOrderList(api: api)
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    private func loadOrderList(api: OrderAPI, append: Bool) async {
        let scenicId = AppStore.shared.session.currentScenicId
        guard scenicId > 0 else {
            finishLoading()
            onShowMessage?("当前景区信息缺失")
            return
        }

        let start = startTime.map { apiDateFormatter.string(from: $0) }
        let end = endTime.map { apiDateFormatter.string(from: $0) }
        let phone = searchText.trimmingCharacters(in: .whitespacesAndNewlines)

        do {
            let response: OrderListResponse<OrderEntity>
            if isScenicAdminReadOnly {
                response = try await api.scenicAdminOrderList(
                    scenicId: scenicId,
                    page: currentPage,
                    orderStatus: tabIndex,
                    startTime: start,
                    endTime: end,
                    userPhone: phone.isEmpty ? nil : phone,
                    isRefined: rTabIndex
                )
            } else {
                response = try await api.photographerOrderList(
                    scenicId: scenicId,
                    page: currentPage,
                    orderStatus: tabIndex,
                    startTime: start,
                    endTime: end,
                    userPhone: phone.isEmpty ? nil : phone,
                    isRefined: rTabIndex
                )
            }
            totalCount = response.total
            if append {
                orderList.append(contentsOf: response.list)
            } else {
                orderList = response.list
            }
            syncOrderSourceSelections()
            canLoadMore = orderList.count < totalCount
        } catch is CancellationError {
            return
        } catch {
            onShowMessage?(error.localizedDescription)
        }
        finishLoading()
    }

    private func performCheckIn(scanResult: String, api: OrderAPI) async {
        guard let jsonBody = appendScenicId(to: scanResult) else {
            onShowMessage?("请扫描正确的二维码")
            return
        }
        do {
            signInResponse = try await api.orderCheckIn(jsonBody: jsonBody)
            notifyStateChange()
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    private func performOrderVerify(jsonBody: String, api: OrderAPI) async {
        do {
            writeOffResponse = try await api.orderVerify(jsonBody: jsonBody)
            notifyStateChange()
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    private func appendScenicId(to scanResult: String) -> String? {
        guard let data = scanResult.data(using: .utf8),
              var json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
            return nil
        }
        json["scenic_id"] = String(AppStore.shared.session.currentScenicId)
        guard let updated = try? JSONSerialization.data(withJSONObject: json),
              let string = String(data: updated, encoding: .utf8) else {
            return nil
        }
        return string
    }

    private func syncOrderSourceSelections() {
        var updated = orderSourceSelections
        for order in orderList {
            if let selection = orderSourceSelection(for: order) {
                updated[order.orderNumber] = selection
            }
        }
        orderSourceSelections = updated
    }

    @discardableResult
    private func abortIfScenicAdminReadOnlyMutation() -> Bool {
        guard isScenicAdminReadOnly else { return false }
        onShowMessage?("景区管理员仅可查看")
        return true
    }

    private func finishLoading() {
        isRefreshing = false
        isLoadingMore = false
        notifyStateChange()
    }

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