//
//  LNRelationManager.swift
//  Lanu
//
//  Created by OneeChan on 2025/12/12.
//

import Foundation


protocol LNRelationManagerNotify {
    func onUserRelationChanged(uid: String, relation: LNUserRelationShip)
    func onMyRelationInfoChanged()
    func onUserBlackListChanged()
}
extension LNRelationManagerNotify {
    func onUserRelationChanged(uid: String, relation: LNUserRelationShip) {}
    func onMyRelationInfoChanged() {}
    func onUserBlackListChanged() {}
}


var myRelationInfo: LNUserRelationStatVO {
    LNRelationManager.shared.myRelationInfo
}


extension String {
    var isInMyBlackList: Bool {
        LNRelationManager.shared.myBlackList.contains(self)
    }
}


struct LNUserRelationShip: OptionSet, Decodable {
    let rawValue: UInt8
    
    static let followed = LNUserRelationShip(rawValue: 1<<0)
    static let fans = LNUserRelationShip(rawValue: 1<<1)
}


class LNRelationManager {
    static var shared = LNRelationManager()
    
    private(set) var myRelationInfo: LNUserRelationStatVO = LNUserRelationStatVO()
    private var relationIsChanged = false
    
    fileprivate var myBlackList = Set<String>()
    
    private init() {
        LNEventDeliver.addObserver(self)
    }
    
    func updateMyRelationInfo(_ info: LNUserRelationStatVO) {
        myRelationInfo = info
        notifyUserRelationInfoChanged()
    }
    
    func reloadRelationInfoIfNeed() {
        guard relationIsChanged else { return }
        
        LNProfileManager.shared.reloadMyProfileDetail()
        relationIsChanged = false
    }
    
    func operateFollow(uid: String, follow: Bool,
                       queue: DispatchQueue = .main,
                       handler: ((Bool) -> Void)?) {
        LNHttpManager.shared.operateFollow(uid: uid, follow: follow) { [weak self] err in
            guard let self else { return }
            if err == nil {
                getRelationWithUser(uid: uid, handler: nil)
                if follow {
                    showToast(.init(key: "A00030"))
                }
            }
            queue.asyncIfNotGlobal {
                handler?(err == nil)
            }
            relationIsChanged = true
        }
    }
    
    func getUserFollowList(next: String, queue: DispatchQueue = .main,
                           handler: @escaping ([LNRelationUserVO]?, String?, Int?) -> Void) {
        LNHttpManager.shared.getUserFollowList(size: 30, next: next) { res, err in
            queue.asyncIfNotGlobal {
                handler(res?.list, res?.next, res?.total)
            }
        }
    }
    
    func getUserFansList(next: String, queue: DispatchQueue = .main,
                         handler: @escaping ([LNRelationUserVO]?, String?, Int?) -> Void) {
        LNHttpManager.shared.getUserFansList(size: 30, next: next) { res, err in
            queue.asyncIfNotGlobal {
                handler(res?.list, res?.next, res?.total)
            }
        }
    }
    
    func getRelationWithUser(uid: String, queue: DispatchQueue = .main,
                             handler: ((LNUserRelationShip?) -> Void)?) {
        LNHttpManager.shared.getRelationWithUser(uid: uid) { [weak self] res, err in
            guard let self else { return }
            queue.asyncIfNotGlobal { [weak self] in
                guard let self else { return }
                handler?(res?.list.first?.relateion)
                
                if let relation = res?.list.first?.relateion {
                    notifyRelationChanged(uid: uid, relation: relation)
                }
            }
        }
    }
}

extension LNRelationManager {
    func blackListUser(uid: String, black: Bool, queue: DispatchQueue = .main, handler: ((Bool) -> Void)?) {
        LNHttpManager.shared.blackListUser(uid: uid, black: black) { [weak self] err in
            guard let self else { return }
            
            queue.asyncIfNotGlobal {
                handler?(err == nil)
            }
            if black {
                myBlackList.insert(uid)
            } else {
                myBlackList.remove(uid)
            }
            notifyUserBlackListChanged()
        }
    }
    
    private func reloadMyBlackList() {
        var next = ""
        var list: [LNUserBlackVO] = []
        func _loadList() {
            LNHttpManager.shared.getBlackList(size: 30, next: next) { [weak self] res, err in
                guard let self else { return }
                guard let res, err == nil else { return }
                
                list.append(contentsOf: res.list)
                next = res.next
                
                if next.isEmpty {
                    myBlackList.formUnion(list.map({ $0.userNo }))
                    notifyUserBlackListChanged()
                } else {
                    _loadList()
                }
            }
        }
        _loadList()
    }
}

extension LNRelationManager: LNAccountManagerNotify {
    func onUserLogin() {
        myRelationInfo = LNUserRelationStatVO()
        myBlackList.removeAll()
        reloadMyBlackList()
    }
}

extension LNRelationManager {
    private func notifyRelationChanged(uid: String, relation: LNUserRelationShip) {
        LNEventDeliver.notifyEvent {
            ($0 as? LNRelationManagerNotify)?.onUserRelationChanged(uid: uid, relation: relation)
        }
    }
    
    private func notifyUserRelationInfoChanged() {
        LNEventDeliver.notifyEvent {
            ($0 as? LNRelationManagerNotify)?.onMyRelationInfoChanged()
        }
    }
    
    private func notifyUserBlackListChanged() {
        LNEventDeliver.notifyEvent {
            ($0 as? LNRelationManagerNotify)?.onUserBlackListChanged()
        }
    }
}
