//
//  WeiboModel.swift
//  WeiboLibrary
//
//  Created by jianghui liu on 2022/5/5.
//

import Foundation
import RxSwift

protocol InfoProperty {
    var code : String {get}
    var name : String {get}
}

struct CityInfo : InfoProperty {
    var code = ""
    var name = ""
    
    static func decodeFromDic(_ dic : [String: String]) -> CityInfo? {
        let values = [String](dic.values)
        let keys = [String](dic.keys)
        return CityInfo(code: keys[0], name: values[0])
    }
}

struct ProvinceInfo : InfoProperty {
    var code = ""
    var name = ""
    var cities = [CityInfo]()
    
    static func decodeFromDic(_ dic : [String: String]) -> ProvinceInfo? {
        return ProvinceInfo(code: [String](dic.keys)[0], name: [String](dic.values)[0])
    }
}

struct CountryInfo : InfoProperty {
    var code = ""
    var name = ""
    var province = [ProvinceInfo]()
    
    static func decodeFromDic(_ dic : [String: String]) -> CountryInfo? {
        return CountryInfo(code: [String](dic.keys)[0], name: [String](dic.values)[0])
    }
}

extension Array {
    func parseCountryList() -> [CountryInfo] {
        var retList = [CountryInfo]()
        
        self.forEach { element in
            guard element is [String : String] else {
                return
            }
            if let country = CountryInfo.decodeFromDic(element as! [String : String]) {
                retList.append(country)
            }
        }
        
        return retList
    }
    
    func parseProvinceList() -> [ProvinceInfo] {
        var retList = [ProvinceInfo]()
        
        self.forEach { element in
            guard element is [String : String] else {
                return
            }
            if let p = ProvinceInfo.decodeFromDic(element as! [String : String]) {
                retList.append(p)
            }
        }
        
        return retList
    }
    
    func parseCityList() -> [CityInfo] {
        var retList = [CityInfo]()
        
        self.forEach { element in
            guard element is [String : String] else {
                return
            }
            if let c = CityInfo.decodeFromDic(element as! [String : String]) {
                retList.append(c)
            }
        }
        
        return retList
    }
}

class WeiboModel {
    /***常驻状态***/
    let sourceId = "2045436852"
    
    let loginState = BehaviorSubject<Bool>(value: false)
    let userName = BehaviorSubject<String?>(value: nil)
    
    /***NEW***/
    let loadSubAction = PublishSubject<Int>()   //bind to cell select
    
    let dataLoader = PublishSubject<[CountryInfo]>()
    
    var countryDataLoader : Observable<[InfoProperty]> {
        get {
            return loadSubAction.asObservable()
//                .asDriver(onErrorJustReturn: 0).asObservable()
                .flatMapLatest { [weak self] i -> Observable<[InfoProperty]> in
                    guard let self = self else {
                        return Observable<[InfoProperty]>.just([])
                    }
                    if i < 0 {  //load country
                        return self.createGetCountryRequest().asObservable()
                            .map { _ in
                                self.getDisplayInfos()
                            }
                    }
                    self.expandOrFold(index: i)
                    if let code = self.getCountryCode(index: i) { //load province
                        return self.createGetProvinceRequest(code).asObservable()
                            .map { _ in
                                self.getDisplayInfos()
                            }
                    }
                    else if let code = self.getProvinceCode(index: i) { //load city
                        return self.createGetCityRequest(code).asObservable()
                            .map { _ in
                                self.getDisplayInfos()
                            }
                    }
                    return Observable<[InfoProperty]>.just(self.getDisplayInfos())
                }
        }
    }
    
    /// 如果指定index 的数据是国家数据，则返回对应的国家code
    func getCountryCode(index : Int) -> String? {
        let country : CountryInfo? = getInfoCode(index: index)
        return country?.code
    }
    
    /// 如果指定index 的数据是省份数据，则返回对应的省份code
    func getProvinceCode(index : Int) -> String? {
        let p : ProvinceInfo? = getInfoCode(index: index)
        return p?.code
    }
    
    func getInfoCode<T>(index : Int) -> T? where T : InfoProperty {
        let allInfo = getDisplayInfos()
        guard index < allInfo.count else {
            return nil
        }
        let info = allInfo[index]
        guard info is T else {
            return nil
        }
        return info as? T
    }
    
    var countryList : [CountryInfo]?
    
    var expandCellCode : [String: Bool] =  [String: Bool]() //cell展开的flag
    deinit {
        print("")
    }
    init() {
        loginState.onNext(WeiboSDK.isWeiboAppInstalled())
    }
    
    /***缓存数据维护接口***/
    func updateProvince(countryCode : String, provinceList : [ProvinceInfo]) {
        guard var countryList = countryList, !countryList.isEmpty else {
            return
        }
        
        for i in 0..<countryList.count {
            if (countryList[i].code == countryCode) {
                countryList[i].province = provinceList
                break
            }
        }
        self.countryList = countryList
    }
    func updateCity(province : String, cityList : [CityInfo]) {
        guard var countryList = countryList, !countryList.isEmpty else {
            return
        }
        
        
        for i in 0..<countryList.count {
            for j in 0..<countryList[i].province.count {
                if (countryList[i].province[j].code == province) {
                    countryList[i].province[j].cities = cityList
                    break
                }
            }
        }
        self.countryList = countryList
    }
    /**缓存 get 接口**/
    func getCacheProvinceList(countryCode : String) -> [ProvinceInfo]? {
        guard let countryList = countryList else {
            return nil
        }
        
        var provinceList :[ProvinceInfo]?
        countryList.forEach { country in
            if country.code == countryCode {
                provinceList = country.province
            }
        }
        return provinceList
    }
    func getCacheCityList(provinceCode : String) -> [CityInfo]? {
        guard let countryList = countryList else {
            return nil
        }
        
        for i in 0..<countryList.count {
            for j in 0..<countryList[i].province.count {
                if (countryList[i].province[j].code == provinceCode) {
                    return countryList[i].province[j].cities
                }
            }
        }
        return nil
    }
    
    /** UI 请求接口 **/
    func createGetCountryRequest() -> Single<[CountryInfo]> {
        //缓存逻辑
        if let countryList = countryList, !countryList.isEmpty {
            return Observable<[CountryInfo]>.of(countryList).asSingle()
        }
        
        let request = URLRequest(url: URL(string: "https://api.weibo.com/2/common/get_country.json?source=\(sourceId)")!)
        let dataRequest = URLSession.shared.rx.data(request: request)
            .map { data -> [CountryInfo] in
                if let arr = try? JSONSerialization.jsonObject(with: data, options: []),
                    let arrTmp : [[String: String]] = arr as? [[String : String]] {
                    self.countryList = arrTmp.parseCountryList()
                    return self.countryList ?? [CountryInfo]()
                }
                throw NSError(domain: "", code: 100001, userInfo: nil)
//                return [CountryInfo]()
            }
        
        return dataRequest.asSingle()
    }
    
    func createGetProvinceRequest(_ countryCode : String) -> Single<[ProvinceInfo]> {
        //缓存逻辑
        if let provinceList = getCacheProvinceList(countryCode: countryCode), !provinceList.isEmpty {
            return Observable<[ProvinceInfo]>.of(provinceList).asSingle()
        }
        
        let request = URLRequest(url: URL(string: "https://api.weibo.com/2/common/get_province.json?source=\(sourceId)&country=\(countryCode)")!)
        let dataRequest = URLSession.shared.rx.data(request: request)
            .map { data -> [ProvinceInfo] in
                _ = String(decoding: data, as: UTF8.self)
                if let arr = try? JSONSerialization.jsonObject(with: data, options: []),
                    let arrTmp : [[String: String]] = arr as? [[String : String]] {
                    if arrTmp.isEmpty {
                        throw NSError(domain: "Pro", code: 100001, userInfo: nil)
                    }
                    let provinces = arrTmp.parseProvinceList()
                    self.updateProvince(countryCode: countryCode, provinceList: provinces)
                    return provinces
                }
                throw NSError(domain: "", code: 100001, userInfo: nil)
//                return [ProvinceInfo]()
            }
        return dataRequest.asSingle()
    }
    
    func createGetCityRequest(_ provinceCode : String) -> Single<[CityInfo]> {
        if let cities = getCacheCityList(provinceCode: provinceCode), !cities.isEmpty {
            return Observable<[CityInfo]>.of(cities).asSingle()
        }
        
        let request = URLRequest(url: URL(string: "https://api.weibo.com/2/common/get_city.json?source=\(sourceId)&province=\(provinceCode)")!)
        let dataRequest = URLSession.shared.rx.data(request: request)
            .map { data -> [CityInfo] in
                if let arr = try? JSONSerialization.jsonObject(with: data, options: []),
                    let arrTmp : [[String: String]] = arr as? [[String : String]] {
                    let cities = arrTmp.parseCityList()
                    self.updateCity(province: provinceCode, cityList: cities)
                    return cities
                }
                return [CityInfo]()
            }
        return dataRequest.asSingle()
    }
}

extension WeiboModel {
    func expandOrFold(index : Int) {
        if let code = self.getCountryCode(index: index) ?? self.getProvinceCode(index: index) {
            self.expandOrFold(code: code)
        }
    }
    func expandOrFold(code : String) {
        if let b = expandCellCode[code] {
            expandCellCode[code] = !b
        }
        else {
            expandCellCode[code] = true
        }
    }
    
    func getDisplayInfos() -> [InfoProperty] {
        var retList = [InfoProperty]()
        
        guard let countryList = countryList else {
            return retList
        }
        
        //先便利 国家，找到展开的国家，则再便利它的省份，找到展开的省，把城市数据插入
        countryList.forEach { country in
            retList.append(country)
            //展开的国家，便利省份
            if let b = expandCellCode[country.code], b {
                country.province.forEach { province in
                    retList.append(province)
                    if let b = expandCellCode[province.code], b {
                        retList.append(contentsOf: province.cities)
                    }
                }
            }
        }
        
        return retList
    }
}

