//
//  LNOrderManager.swift
//  Lanu
//
//  Created by OneeChan on 2025/11/6.
//

import Foundation


protocol LNOrderManagerNotify {
    func onOrderInfoChanged(orderId: String)
    func onMyDiscountInfoChanged(info: LNOrderDiscountVO?)
}
extension LNOrderManagerNotify {
    func onOrderInfoChanged(orderId: String) { }
    func onMyDiscountInfoChanged(info: LNOrderDiscountVO?) { }
}

enum LNOrderErrorCode: Int {
    case NotEnoughMoney = 100018
    case NotEnoughMoneyButCanExchange = 50002
}

protocol LNOrderProtocol {
    var buyerUserNo: String { get }
    var refundApply: Bool { get }
    var status: LNOrderStatus { get }
}
extension LNOrderProtocol {
    var statusUI: (title: String, icon: UIImage) {
        let isCreator = buyerUserNo.isMyUid
        
        if refundApply {
            return if isCreator {
                (.init(key: "A00049"), .icImChatOrderPending)
            } else {
                (.init(key: "A00051"), .icImChatOrderRefunding)
            }
        }
        
        return switch status {
        case .created, .waitingForAccept:
            if isCreator {
                (.init(key: "A00053"), .icImChatOrderSuccess)
            } else {
                (.init(key: "A00055"), .icImChatOrderPending)
            }
        case .completed: (.init(key: "A00057"), .icImChatOrderComplete)
        case .refunded: (.init(key: "A00060"), .icImChatOrderRefunded)
        case .accepted: (.init(key: "A00062"), .icImChatOrderAccepted)
        case .rejected: (.init(key: "A00065"), .icImChatOrderCancel)
        case .servicing: (.init(key: "A00068"), .icImChatOrderProcessing)
        case .serviceDone: (.init(key: "A00070"), .icImChatOrderComplete)
        case .cancelled: (.init(key: "A00071"), .icImChatOrderCancel)
        }
    }
}

class LNOrderManager {
    static var shared = LNOrderManager()
    static let orderExtraMaxLength = 150
    static let orderProtestMaxLength = 500
    static let orderRefundMaxLength = 500
    static let orderCommentMaxLength = 200
    
    private var discount: LNOrderDiscountVO?
    
    func discountFor(_ price: Double) -> Double? {
        if let discount, discount.hasChance, discount.eligiblePrice == price {
            discount.discountRate
        } else {
            nil
        }
    }
    
    private init() {
        LNEventDeliver.addObserver(self)
    }
}


// MARK: 订单信息
extension LNOrderManager {
    func getList(size: Int, next: String? = nil, queue: DispatchQueue = .main,
                 handler: @escaping ([LNOrderListItemVO]?, String?) -> Void) {
        LNHttpManager.shared.getOrderList(size: size, next: next ?? "") { res, err in
            queue.asyncIfNotGlobal {
                handler(res?.list, res?.next)
            }
        }
    }
    
    func getOrderDetail(orderId: String, queue: DispatchQueue = .main,
                        handler: @escaping (LNOrderDetailResponse?) -> Void) {
        LNHttpManager.shared.getOrderDetail(orderId: orderId) { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
        }
    }
    
    func getRecordList(size: Int, next: String? = nil, queue: DispatchQueue = .main,
                       handler: @escaping ([LNOrderRecordItemVO]?, String) -> Void) {
        LNHttpManager.shared.getOrderRecordList(size: size, next: next ?? "") { res, err in
            guard err == nil, let res else {
                queue.asyncIfNotGlobal {
                    handler(nil, "")
                }
                return
            }
            queue.asyncIfNotGlobal {
                handler(res.list, res.next)
            }
        }
    }
    
    func getUnfinishedOrderWith(uid: String, size: Int, next: String?,
                                queue: DispatchQueue = .main,
                                handler: @escaping ([LNUnfinishedOrderVO]?, String?) -> Void) {
        LNHttpManager.shared.getUnfinishedOrderWith(uid: uid, size: size, next: next ?? "") { res, err in
            queue.asyncIfNotGlobal {
                handler(res?.list, res?.next)
            }
        }
    }
    
    func getLastOrder(queue: DispatchQueue = .main, handler: @escaping (LNLastOrderResponse?) -> Void) {
        LNHttpManager.shared.getLastOrder { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
        }
    }
}


// MARK: 订单操作
extension LNOrderManager {
    func createOrder(skillId: String, count: Int,
                     remark: String, scene: LNOrderScene = .normal,
                     queue: DispatchQueue = .main,
                     handler: @escaping (String?) -> Void)
    {
        LNHttpManager.shared.createOrderBySkill(skillId: skillId, count: count, remark: remark, scene: scene)
        { [weak self] res, err in
            guard let self else { return }
            if let res, err == nil {
                LNPurchaseManager.shared.reloadWalletInfo()
                notifyOrderInfoChanged(orderId: res.orderNo)
                reloadMyOrderDiscountInfo()
            }
            queue.asyncIfNotGlobal {
                handler(res?.orderNo)
            }
            
            if case .serverError(let code, let err) = err {
                runOnMain {
                    if code == LNOrderErrorCode.NotEnoughMoney.rawValue {
                        let panel = LNPurchasePanel()
                        panel.update(.coin)
                        panel.popup()
                        showToast(err)
                    } else {
                        showToast(err)
                    }
                }
            }
        }
    }
    
    func cancelOrder(orderId: String,
                     queue: DispatchQueue = .main,
                     handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.cancelOrder(orderId: orderId) { [weak self] err in
            guard let self else { return }
            
            queue.asyncIfNotGlobal { [weak self] in
                handler(err == nil)
                
                guard let self else { return }
                if err == nil {
                    notifyOrderInfoChanged(orderId: orderId)
                    reloadMyOrderDiscountInfo()
                    LNPurchaseManager.shared.reloadWalletInfo()
                } else {
                    showToast(err?.errorDesc)
                }
            }
        }
    }
    
    func finishOrder(orderId: String, queue: DispatchQueue = .main,
                     handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.finishOrder(orderId: orderId) { [weak self] err in
            guard let self else { return }
            queue.asyncIfNotGlobal { [weak self] in
                handler(err == nil)
                
                guard let self else { return }
                if err == nil {
                    notifyOrderInfoChanged(orderId: orderId)
                } else {
                    showToast(err?.errorDesc)
                }
            }
        }
    }
    
    func refundOrder(orderId: String, reason: String,
                     attachments: [String], queue: DispatchQueue = .main,
                     handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.refundOrder(orderId: orderId, reason: reason, attachments: attachments)
        { [weak self] err in
            guard let self else { return }
            queue.asyncIfNotGlobal { [weak self] in
                handler(err == nil)
                
                guard let self else { return }
                if err == nil {
                    notifyOrderInfoChanged(orderId: orderId)
                    reloadMyOrderDiscountInfo()
                } else {
                    showToast(err?.errorDesc)
                }
            }
        }
    }
    
    func commentOrder(orderId: String, star: Double, comment: String,
                      queue: DispatchQueue = .main,
                      handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.commentOrder(
            orderId: orderId, star: star, comment: comment)
        { [weak self] err in
            guard let self else { return }
            queue.asyncIfNotGlobal { [weak self] in
                handler(err == nil)
                guard let self else { return }
                if err == nil {
                    notifyOrderInfoChanged(orderId: orderId)
                } else {
                    showToast(err?.errorDesc)
                }
            }
        }
    }
    
    func rejectOrder(orderId: String, queue: DispatchQueue = .main,
                     handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.rejectOrder(orderId: orderId) { [weak self] err in
            guard let self else { return }
            queue.asyncIfNotGlobal { [weak self] in
                handler(err == nil)
                
                guard let self else { return }
                if err == nil {
                    notifyOrderInfoChanged(orderId: orderId)
                } else {
                    showToast(err?.errorDesc)
                }
            }
        }
    }
    
    func acceptOrder(orderId: String, queue: DispatchQueue = .main,
                     handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.acceptOrder(orderId: orderId) { [weak self] err in
            guard let self else { return }
            queue.asyncIfNotGlobal { [weak self] in
                handler(err == nil)
                guard let self else { return }
                if err == nil {
                    notifyOrderInfoChanged(orderId: orderId)
                } else {
                    showToast(err?.errorDesc)
                }
            }
        }
    }
    
    func startOrderService(orderId: String, queue: DispatchQueue = .main,
                           handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.startOrderService(orderId: orderId) { [weak self] err in
            guard let self else { return }
            queue.asyncIfNotGlobal { [weak self] in
                handler(err == nil)
                guard let self else { return }
                if err == nil {
                    notifyOrderInfoChanged(orderId: orderId)
                } else {
                    showToast(err?.errorDesc)
                }
            }
        }
    }
    
    func finishOrderService(orderId: String, queue: DispatchQueue = .main,
                            handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.finishOrderService(orderId: orderId) { [weak self] err in
            guard let self else { return }
            queue.asyncIfNotGlobal { [weak self] in
                handler(err == nil)
                guard let self else { return }
                if err == nil {
                    notifyOrderInfoChanged(orderId: orderId)
                } else {
                    showToast(err?.errorDesc)
                }
            }
        }
    }
    
    func protestOrder(orderId: String, reason: String,
                      queue: DispatchQueue = .main,
                      attachments: [String], handler: @escaping (Bool) -> Void)
    {
        LNHttpManager.shared.protestOrder(orderId: orderId, reason: reason, attachments: attachments)
        { [weak self] err in
            guard let self else { return }
            queue.asyncIfNotGlobal { [weak self] in
                handler(err == nil)
                
                guard let self else { return }
                if err == nil {
                    notifyOrderInfoChanged(orderId: orderId)
                } else {
                    showToast(err?.errorDesc)
                }
            }
        }
    }
}


// MARK: 二维码
extension LNOrderManager {
    func createOrderQR(skillId: String,
                       count: Int, type: LNOrderSource,
                       queue: DispatchQueue = .main,
                       handler: @escaping (String?) -> Void) {
        LNHttpManager.shared.createOrderQR(skillId: skillId, count: count, type: type) { [weak self] data, err in
            queue.asyncIfNotGlobal {
                handler(data?.qrCode)
            }
            if let err {
                showToast(err.errorDesc)
            } else if let self {
                reloadMyOrderDiscountInfo()
            }
        }
    }
    
    func getQRDetail(data: String,
                     queue: DispatchQueue = .main,
                     handler: @escaping (LNQRCodeDetailResponse?) -> Void) {
        LNHttpManager.shared.getQRDetail(data: data) { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
            
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func createQRCodeOrder(data: String, count: Int,
                           extra: String, scene: LNOrderScene = .normal,
                           queue: DispatchQueue = .main,
                           handler: @escaping (String?) -> Void) {
        LNHttpManager.shared.createQROrder(data: data, count: count, extra: extra, scene: scene) { [weak self] res, err in
            queue.asyncIfNotGlobal {
                handler(res?.orderNo)
            }
            
            if let err {
                showToast(err.errorDesc)
            } else if let self {
                LNPurchaseManager.shared.reloadWalletInfo()
                reloadMyOrderDiscountInfo()
            }
        }
    }
}

// MARK: 折扣
extension LNOrderManager {
    func reloadMyOrderDiscountInfo() {
        LNHttpManager.shared.fetchOrderDiscount { [weak self] info, err in
            guard let self else { return }
            if err != nil { return }
            discount = info
            notifyDiscountInfoChange(info: info)
        }
    }
}

extension LNOrderManager: LNAccountManagerNotify {
    func onUserLogin() {
        reloadMyOrderDiscountInfo()
    }
}

extension LNOrderManager {
    private func notifyOrderInfoChanged(orderId: String) {
        LNEventDeliver.notifyEvent {
            ($0 as? LNOrderManagerNotify)?.onOrderInfoChanged(orderId: orderId)
        }
    }
    
    private func notifyDiscountInfoChange(info: LNOrderDiscountVO?) {
        LNEventDeliver.notifyEvent {
            ($0 as? LNOrderManagerNotify)?.onMyDiscountInfoChanged(info: info)
        }
    }
}
