//
//  LNGameMateManager.swift
//  Lanu
//
//  Created by OneeChan on 2025/11/20.
//

import Foundation


protocol LNGameMateManagerNotify {
    func onGameMateManagerInfoChanged()
    func onGameTypesChanged()
    
    func onAutoReplyCreated(item: LNAutoReplyVO)
    func onAutoReplyDeleted(id: String)
    func onAutoReplyModified(item: LNAutoReplyVO)
}
extension LNGameMateManagerNotify {
    func onGameMateManagerInfoChanged() { }
    func onGameTypesChanged() { }
    
    func onAutoReplyCreated(item: LNAutoReplyVO) { }
    func onAutoReplyDeleted(id: String) { }
    func onAutoReplyModified(item: LNAutoReplyVO) { }
}

var myGameMateInfo: LNGameMateManagerInfo? {
    LNGameMateManager.shared.myGameMateInfo
}

class LNGameMateManager {
    static let shared = LNGameMateManager()
    private(set) var curGameTypes: [LNGameTypeItemVO] = []
    private(set) var gameFilterMap: [String: [LNSkillFilterField]] = [:]
    
    private(set) var myGameMateInfo: LNGameMateManagerInfo?
    
    static let gameSelectionMaxCount = 5
    static let AutoReplayMaxInput = 500
    
    func gameCategory(for code: String) -> LNGameCategoryItemVO? {
        for type in curGameTypes {
            if let item = type.children.first(where: { $0.code == code }) {
                return item
            }
        }
        return nil
    }
    
    func gameFilter(for code: String) -> [LNSkillFilterField] {
        gameFilterMap[code] ?? []
    }
    
    private init() {
        LNEventDeliver.addObserver(self)
    }
}

// MARK: 陪玩师信息拉取
extension LNGameMateManager {
    func getUserSkills(uid: String, queue: DispatchQueue = .main,
                       handler: @escaping ([LNGameMateSkillVO]?) -> Void) {
        LNHttpManager.shared.getUserSkills(uid: uid) { res, err in
            guard err == nil, let res else {
                queue.asyncIfNotGlobal {
                    handler(nil)
                }
                return
            }
            queue.asyncIfNotGlobal {
                handler(res.list)
            }
        }
    }
    
    func getSkillDetail(skillId: String, queue: DispatchQueue = .main,
                        handler: @escaping (LNGameMateSkillDetailVO?) -> Void) {
        LNHttpManager.shared.getSkillDetail(skillId: skillId) { res, err in
            guard err == nil, let res else {
                queue.asyncIfNotGlobal {
                    handler(nil)
                }
                return
            }
            queue.asyncIfNotGlobal {
                handler(res)
            }
        }
    }
    
    func scoreGameMate(uid: String, score: Int, queue: DispatchQueue = .main,
                       handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.scoreGameMate(uid: uid, score: score) { err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
        }
    }
    
    func getSkillCommentList(id: String, next: String? = nil,
                             queue: DispatchQueue = .main,
                             handler: @escaping (LNSkillCommentListResponse?) -> Void) {
        LNHttpManager.shared.getSkillCommentList(id: id, size: 30, next: next ?? "") { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func getGameMateList(
        topCategory: String, category: String?, filter: LNGameMateFilter, size: Int,
        next: String?, queue: DispatchQueue = .main,
        handler: @escaping ([LNGameMateListItemVO]?, String?) -> Void) {
            LNHttpManager.shared.getGameMateList(
                topCategory: topCategory, category: category,
                filter: filter, size: size, next: next ?? "")
            { res, err in
                queue.asyncIfNotGlobal {
                    handler(res?.list, res?.next)
                }
                
                if let err {
                    showToast(err.errorDesc)
                }
            }
            
            LNRoomManager.shared.reloadHallEntrance()
        }
    
    func searchGameMate(keyword: String, next: String, queue: DispatchQueue = .main,
                        handler: @escaping ([LNGameMateSearchResultVO]?, String?) -> Void) {
        LNHttpManager.shared.searchGameMate(keyword: keyword, size: 30, next: next) { res, err in
            queue.asyncIfNotGlobal {
                handler(res?.list, res?.next)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func mixSearch(keyword: String, queue: DispatchQueue = .main,
                   handler: @escaping (LNMixSearchResponse?) -> Void) {
        LNHttpManager.shared.mixSearch(keyword: keyword) { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
}

// MARK: 陪玩师类别
extension LNGameMateManager {
    func getGameTypeList(queue: DispatchQueue = .main,
                         handler: @escaping ([LNGameTypeItemVO]?) -> Void) {
        LNHttpManager.shared.getGameCategories { [weak self] res, err in
            guard let self else { return }
            guard err == nil, let res else {
                queue.asyncIfNotGlobal {
                    handler(nil)
                }
                return
            }
            reloadGameFilterConfig()
            
            curGameTypes = res.list
            queue.asyncIfNotGlobal {
                handler(res.list)
            }
            notifyGameTypesChanged()
        }
    }
    
    func reloadGameFilterConfig() {
        LNHttpManager.shared.getGameFilterConfig { [weak self] list, err in
            guard let self else { return }
            guard let list else { return }
            gameFilterMap.removeAll()
            for item in list.list {
                gameFilterMap[item.code] = item.filterFields
            }
        }
    }
}

// MARK: 陪玩师入驻
extension LNGameMateManager {
    func getJoinGameMateInfo(queue: DispatchQueue = .main,
                             handler: @escaping (LNJoinUsInputInfosResponse?) -> Void) {
        LNHttpManager.shared.getJoinGameMateInfo { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func setJoinGameMateBaseInfo(info: LNJoinUsBaseInfoVO, queue: DispatchQueue = .main,
                                 handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.setJoinGameMateBaseInfo(info: info) { res, err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func getCreateSkillFields(id: String, queue: DispatchQueue = .main, handler: @escaping (LNCreateSkillInputFieldsVO?) -> Void) {
        LNHttpManager.shared.getCreateSkillFields(id: id) { res, err in
            queue.asyncIfNotGlobal {
                if let res {
                    guard !res.fields.isEmpty else {
                        showToast(.init(key: "B00060"))
                        handler(nil)
                        return
                    }
                    guard res.isAvailable else {
                        showToast(.init(key: "B00058"))
                        handler(nil)
                        return
                    }
                }
                handler(res)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func createSkill(info: LNCreateSkillFieldsInfo,
                     queue: DispatchQueue = .main,
                     handler: @escaping (Bool) -> Void)
    {
        LNHttpManager.shared.createSkill(info: info) { err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
}

// MARK: 陪玩师管理
extension LNGameMateManager {
    func getGameMateManagerInfo(
        queue: DispatchQueue = .main,
        handler: ((LNGameMateManagerInfo?) -> Void)? = nil)
    {
        LNHttpManager.shared.getGameMateManagerInfo { [weak self] info, err in
            queue.asyncIfNotGlobal {
                handler?(info)
            }
            if let err {
                showToast(err.errorDesc)
            } else {
                guard let self else { return }
                myGameMateInfo = info
                notifyUserGameMateManagerInfoChanged()
            }
        }
    }
    
    func enableGameMate(open: Bool,
                        queue: DispatchQueue = .main,
                        handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.enableGameMate(open: open) { [weak self] err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            if let err {
                showToast(err.errorDesc)
            } else {
                guard let self else { return }
                getGameMateManagerInfo()
            }
        }
    }
    
    func getOrderAccetpConfig(
        queue: DispatchQueue = .main,
        handler: @escaping (LNOrderAcceptConfig?) -> Void)
    {
        LNHttpManager.shared.getOrderAccetpConfig { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func setOrderAcceptConfig(
        config: LNOrderAcceptConfig,
        queue: DispatchQueue = .main,
        handler: @escaping (Bool) -> Void)
    {
        LNHttpManager.shared.setOrderAcceptConfig(config: config) { err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func getMySkillList(
        queue: DispatchQueue = .main,
        handler: @escaping (LNMySkillListResponse?) -> Void)
    {
        LNHttpManager.shared.getMySkillList { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func getSkillSwitchInfo(id: String,
                            queue: DispatchQueue = .main,
                            handler: @escaping (LNSkillSwitchResponse?) -> Void) {
        LNHttpManager.shared.getSkillSwitchInfo(id: id) { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func enableSkill(skillId: String, open: Bool, mainSkill: Bool? = nil,
                     queue: DispatchQueue = .main,
                     handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.enableSkill(skillId: skillId, open: open, mainSkill: mainSkill) { err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            if let err {
                showToast(err.errorDesc)
            } else {
                LNProfileManager.shared.reloadMyProfileDetail()
            }
        }
    }
    
    func getVisitorsList(next: String? = nil,
                         queue: DispatchQueue = .main,
                         handler: @escaping ([LNVisitorItemVO]?, String?) -> Void) {
        LNHttpManager.shared.getVisitorsList(next: next ?? "", size: 30) { res, err in
            queue.asyncIfNotGlobal {
                handler(res?.list, res?.next)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func getSkillEditFields(id: String,
                            queue: DispatchQueue = .main,
                            handler: @escaping (LNSkillEditFieldsResponse?) -> Void) {
        LNHttpManager.shared.getSkillEditFields(id: id) { res, err in
            queue.asyncIfNotGlobal {
                handler(res)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func commitSkillEdit(info: LNEditSkillFieldsInfo,
                         queue: DispatchQueue = .main,
                         handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.commitSkillEdit(info: info) { err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
}

// MARK: 欢迎语(自动回复)
extension LNGameMateManager {
    func enableAutoReplay(on: Bool, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.enableAutoReplay(on: on) { err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func getAutoReplayList(queue: DispatchQueue = .main, handler: @escaping (LNAutoReplyResponse?) -> Void) {
        LNHttpManager.shared.getAutoReplayList { list, err in
            queue.asyncIfNotGlobal {
                handler(list)
            }
            if let err {
                showToast(err.errorDesc)
            }
        }
    }
    
    func deleteAutoReplay(id: String, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.deleteAutoReplay(id: id) { err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            
            if let err {
                showToast(err.errorDesc)
            } else {
                Self.notifyAutoReplayDeleted(id: id)
            }
        }
    }
    
    func createAutoReplay(item: LNAutoReplyVO, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.createAutoReplay(item: item) { err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            if let err {
                showToast(err.errorDesc)
            } else {
                Self.notifyAutoReplayCreated(item: item)
            }
        }
    }
    
    func updateAutoReplay(item: LNAutoReplyVO, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.updateAutoReplay(item: item) { err in
            queue.asyncIfNotGlobal {
                handler(err == nil)
            }
            if let err {
                showToast(err.errorDesc)
            } else {
                Self.notifyAutoReplayModified(item: item)
            }
        }
    }
    
    func triggerAutoReplayIfNeed(uid: String) {
        LNHttpManager.shared.triggerAutoReplayIfNeed(uid: uid) { _ in }
    }
    
    func markUseAutoReplay(uid: String) {
        LNHttpManager.shared.markUseAutoReplay(uid: uid) { _ in }
    }
    
    func fetchAutoReplyQuota(uid: String, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) {
        LNHttpManager.shared.fetchAutoReplyQuota(uid: uid) { res, err in
            queue.asyncIfNotGlobal {
                if let err {
                    showToast(err.errorDesc)
                    handler(false)
                } else if let res {
                    if res.playmateQuotaCount > 0 && res.userQuotaCount > 0 {
                        handler(true)
                    } else {
                        showToast(.init(key: "A00350"))
                        handler(false)
                    }
                } else {
                    handler(false)
                }
            }
        }
    }
}

// MARK: 潜在用户
extension LNGameMateManager {
   func getPotentialUsers(queue: DispatchQueue = .main, handler: @escaping (LNPotentialUsersResponse?) -> Void) {
       LNHttpManager.shared.getPotentialUsers { res, err in
           queue.asyncIfNotGlobal {
               handler(res)
           }
           if let err {
               showToast(err.errorDesc)
           }
       }
   }
}


extension LNGameMateManager: LNProfileManagerNotify {
    func onUserInfoChanged(userInfo: LNUserProfileVO) {
        guard userInfo.userNo.isMyUid else { return }
        
        if userInfo.playmate {
            getGameMateManagerInfo()
        }
    }
}

extension LNGameMateManager {
    private func notifyUserGameMateManagerInfoChanged() {
        LNEventDeliver.notifyEvent { ($0 as? LNGameMateManagerNotify)?.onGameMateManagerInfoChanged() }
    }
    
    private func notifyGameTypesChanged() {
        LNEventDeliver.notifyEvent {
            ($0 as? LNGameMateManagerNotify)?.onGameTypesChanged()
        }
    }
    
    private static func notifyAutoReplayCreated(item: LNAutoReplyVO) {
        LNEventDeliver.notifyEvent {
            ($0 as? LNGameMateManagerNotify)?.onAutoReplyCreated(item: item)
        }
    }
    
    private static func notifyAutoReplayDeleted(id: String) {
        LNEventDeliver.notifyEvent {
            ($0 as? LNGameMateManagerNotify)?.onAutoReplyDeleted(id: id)
        }
    }
    
    
    private static func notifyAutoReplayModified(item: LNAutoReplyVO) {
        LNEventDeliver.notifyEvent {
            ($0 as? LNGameMateManagerNotify)?.onAutoReplyModified(item: item)
        }
    }
}
