//
//  KMDesignToken.swift
//  PDF Reader Pro
//
//  Created by wanjun on 2022/12/21.
//

import Cocoa

@objcMembers class KMDesignToken: NSObject {
    
    private static let  sharedInstance = KMDesignToken()
    @objc class var shared: KMDesignToken {
        return sharedInstance
    }
    var jsonPaser: KMJSONParser?
    var finalDict: [String : Any] = [:]

    func parserExcel(withPath path: String) -> Void {
        let data = try? Data(contentsOf: URL(fileURLWithPath: Bundle.main.path(forResource: "$metadata", ofType: "json")!))
        let jsonData = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)
        let jsonDict = jsonData as! [String : [String]]
                
        jsonPaser = KMJSONParser.defaultJSONParser_JSONParser
        jsonPaser?.parseFilePaths = jsonDict["tokenSetOrder"]
        jsonPaser?.parseOutType = .ArrayObj
        jsonPaser?.delete = self
        jsonPaser?.parse()
    }
    
    func tokenUsesAction(withToken token: String) -> [String : Any] {
        return finalDict[token] as! [String : Any]
    }
    
    // MARK: Design Token Uses
/**
    在仅知道Token值,或其余快捷接口不满足当前类型时,使用此方法。当其余接口处理失败后,自动调用此方法返回数据
     - parameter token: 传入获取的Design Token
     - returns: 返回 KMDesignTokenValue 数据模型
*/
    func tokenUsesModel(withToken token: String) -> KMDesignTokenValue {
        let tokenDict = tokenUsesAction(withToken: token)
        var model = KMDesignTokenValue.init()
        let allKey = tokenDict.keys
        if allKey.contains("sizing") {
            model.sizing = tokenDict["sizing"] as Any
        }
        if allKey.contains("height") {
            model.height = tokenDict["height"] as Any
        }
        if allKey.contains("width") {
            model.width = tokenDict["width"] as Any
        }
        if allKey.contains("spacing") {
            model.spacing = tokenDict["spacing"] as Any
        }
        if allKey.contains("verticalPadding") {
            model.verticalPadding = tokenDict["verticalPadding"] as Any
        }
        if allKey.contains("horizontalPadding") {
            model.horizontalPadding = tokenDict["horizontalPadding"] as Any
        }
        if allKey.contains("paddingTop") {
            model.paddingTop = tokenDict["paddingTop"] as Any
        }
        if allKey.contains("paddingRight") {
            model.paddingRight = tokenDict["paddingRight"] as Any
        }
        if allKey.contains("paddingBottom") {
            model.paddingBottom = tokenDict["paddingBottom"] as Any
        }
        if allKey.contains("paddingLeft") {
            model.paddingLeft = tokenDict["paddingLeft"] as Any
        }
        if allKey.contains("itemSpacing") {
            model.itemSpacing = tokenDict["itemSpacing"] as Any
        }
        if allKey.contains("fill") {
            model.fill = tokenDict["fill"] as Any
        }
        if allKey.contains("border") {
            model.border = tokenDict["border"] as Any
        }
        if allKey.contains("borderColor") {
            model.borderColor = tokenDict["borderColor"] as Any
        }
        if allKey.contains("borderTop") {
            model.borderTop = tokenDict["borderTop"] as Any
        }
        if allKey.contains("borderRight") {
            model.borderRight = tokenDict["borderRight"] as Any
        }
        if allKey.contains("borderBottom") {
            model.borderBottom = tokenDict["borderBottom"] as Any
        }
        if allKey.contains("borderLeft") {
            model.borderLeft = tokenDict["borderLeft"] as Any
        }
        if allKey.contains("borderRadius") {
            model.borderRadius = tokenDict["borderRadius"] as Any
        }
        if allKey.contains("borderRadiusTopLeft") {
            model.borderRadiusTopLeft = tokenDict["borderRadiusTopLeft"] as Any
        }
        if allKey.contains("borderRadiusTopRight") {
            model.borderRadiusTopRight = tokenDict["borderRadiusTopRight"] as Any
        }
        if allKey.contains("borderRadiusBottomRight") {
            model.borderRadiusBottomRight = tokenDict["borderRadiusBottomRight"] as Any
        }
        if allKey.contains("borderRadiusBottomLeft") {
            model.borderRadiusBottomLeft = tokenDict["borderRadiusBottomLeft"] as Any
        }
        if allKey.contains("borderWidth") {
            model.borderWidth = tokenDict["borderWidth"] as Any
        }
        if allKey.contains("borderWidthTop") {
            model.borderWidthTop = tokenDict["borderWidthTop"] as Any
        }
        if allKey.contains("borderWidthRight") {
            model.borderWidthRight = tokenDict["borderWidthRight"] as Any
        }
        if allKey.contains("borderWidthBottom") {
            model.borderWidthBottom = tokenDict["borderWidthBottom"] as Any
        }
        if allKey.contains("borderWidthLeft") {
            model.borderWidthLeft = tokenDict["borderWidthLeft"] as Any
        }
        if allKey.contains("boxShadow") {
            model.boxShadow = tokenDict["boxShadow"] as Any
        }
        if allKey.contains("typography") {
            model.typography = tokenDict["typography"] as Any
        }
        return model
    }
        
    
/**
    当使用者希望传入控件/约束后绑定值时调用此方法。
    仅支持系统控件默认属性/自定义控件的属性绑定,所以不支持设置以下属性 【borderTop】、【borderRight】、【borderBottom】、【borderLeft】、【borderRadiusTopLeft】、【borderRadiusTopRight】、【borderRadiusBottomRight】、【borderRadiusBottomLeft】、【borderWidthTop】、【borderWidthRight】、【borderWidthBottom】、【borderWidthLeft】
     - parameter token:             传入Design Token
     - parameter sizing:            包含 sizing 属性的控件;支持控件【NSTextField】、
     - parameter height:            考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【高度】赋值
     - parameter width:             考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【宽度】赋值
     - parameter spacing:           考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 上下左右 距离】赋值
     - parameter verticalPadding:   考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 垂直(上下)距离】赋值
     - parameter horizontalPadding: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 水平(左右)距离】赋值
     - parameter paddingTop:        考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 上 边距】赋值
     - parameter paddingRight:      考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 右 边距】赋值
     - parameter paddingBottom:     考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 下 边距】赋值
     - parameter paddingLeft:       考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 左 边距】赋值
     - parameter itemSpacing:       组件内多个控件间距,多个控件水平排列,属于水平间距;多个控件垂直排列,属于垂直间距;建议传入【NSLayoutConstraint】 类型
     - parameter fill:              传入需要调整【填充颜色】的控件;支持控件
     - parameter border:            传入需要调整【边框属性合集,包括边框颜色、边框宽度、边框样式(虚线/直线)】的控件;支持控件
     - parameter borderColor:       传入需要调整【边框颜色】的控件;支持控件
     - parameter borderRadius:      传入需要调整【边框圆角】的控件;支持控件
     - parameter borderWidth:       传入需要调整【边框宽度】的控件;支持控件
     - parameter boxShadow:         传入需要调整【包含x/y 倾斜度、blur(模糊间距)】的控件;支持控件
     - parameter typography:        传入需要调整【字体合集,包含字体/大小/字重/行高】的控件;支持控件

     - returns: 当处理成功时返回Bool值,若处理失败,则返回 KMDesignTokenValue 数据模型
*/
    func designTokenUsesAction(withToken token: String,
                               sizing           : Any = "",
                               height           : Any = "",
                               width            : Any = "",
                               spacing          : Any = "",
                               verticalPadding  : Any = "",
                               horizontalPadding: Any = "",
                               paddingTop       : Any = "",
                               paddingRight     : Any = "",
                               paddingBottom    : Any = "",
                               paddingLeft      : Any = "",
                               itemSpacing      : Any = "",
                               fill             : Any = "",
                               border           : Any = "",
                               borderColor      : Any = "",
                               borderRadius     : Any = "",
                               borderWidth      : Any = "",
                               boxShadow        : Any = "",
                               typography       : Any = "") -> Any {
        if (sizing              is String) &&
           (height              is String) &&
           (width               is String) &&
           (spacing             is String) &&
           (verticalPadding     is String) &&
           (horizontalPadding   is String) &&
           (paddingTop          is String) &&
           (paddingRight        is String) &&
           (paddingBottom       is String) &&
           (paddingLeft         is String) &&
           (itemSpacing         is String) &&
           (fill                is String) &&
           (border              is String) &&
           (borderColor         is String) &&
           (borderRadius        is String) &&
           (borderWidth         is String) &&
           (boxShadow           is String) &&
           (typography          is String) {
            return tokenUsesModel(withToken: token)
        } else {
            let tokenDict = tokenUsesAction(withToken: token)
            let allKey = tokenDict.keys
            if allKey.contains("sizing") {
                let sizingNode = tokenDict["sizing"]
                if nodeIsEmpty(control: sizing, node: sizingNode as Any) {
                    if sizingNodeUsesAction(control: sizing, node: sizingNode as Any) {
                        KMPrint("sizing node user success")
                    } else {
                        return tokenUsesModel(withToken: token)
                    }
                } else {
                    return tokenUsesModel(withToken: token)
                }
            }
            if allKey.contains("height")            ||
               allKey.contains("width")             ||
               allKey.contains("spacing")           ||
               allKey.contains("verticalPadding")   ||
               allKey.contains("horizontalPadding") ||
               allKey.contains("paddingTop")        ||
               allKey.contains("paddingRight")      ||
               allKey.contains("paddingBottom")     ||
               allKey.contains("paddingLeft")       ||
               allKey.contains("itemSpacing") {
                var node: Any!
                var control: Any!
                if allKey.contains("height") {
                    node = tokenDict["height"] as Any
                    control = height
                } else if allKey.contains("width") {
                    node = tokenDict["width"] as Any
                    control = width
                } else if allKey.contains("spacing") {
                    node = tokenDict["spacing"] as Any
                    control = spacing
                } else if allKey.contains("verticalPadding") {
                    node = tokenDict["verticalPadding"] as Any
                    control = verticalPadding
                } else if allKey.contains("horizontalPadding") {
                    node = tokenDict["horizontalPadding"] as Any
                    control = horizontalPadding
                } else if allKey.contains("paddingTop") {
                    node = tokenDict["paddingTop"] as Any
                    control = paddingTop
                } else if allKey.contains("paddingRight") {
                    node = tokenDict["paddingRight"] as Any
                    control = paddingRight
                } else if allKey.contains("paddingBottom") {
                    node = tokenDict["paddingBottom"] as Any
                    control = paddingBottom
                } else if allKey.contains("paddingLeft") {
                    node = tokenDict["paddingLeft"] as Any
                    control = paddingLeft
                } else if allKey.contains("itemSpacing") {
                    node = tokenDict["itemSpacing"] as Any
                    control = itemSpacing
                }
                if nodeIsEmpty(control: control as Any, node: node as Any) {
                    if layoutConstraintNodeUsesAction(control: control as Any, node: node as Any) {
                        KMPrint("node user success")
                    } else {
                        return tokenUsesModel(withToken: token)
                    }
                } else {
                    return tokenUsesModel(withToken: token)
                }
            }

            if allKey.contains("fill") {
                let fillNode = tokenDict["fill"]
                if nodeIsEmpty(control: fill, node: fillNode as Any) {
                    if fillNodeUsesAction(control: fill, node: fillNode as Any) {
                        KMPrint("fill node user success")
                    } else {
                        return tokenUsesModel(withToken: token)
                    }
                } else {
                    return tokenUsesModel(withToken: token)
                }
            }
            if allKey.contains("border") {
                let borderNode = tokenDict["border"]
                if nodeIsEmpty(control: border, node: borderNode as Any) {
                    if borderNodeUsesAction(control: border, node: borderNode as Any) {
                        KMPrint("border node user success")
                    } else {
                        return tokenUsesModel(withToken: token)
                    }
                } else {
                    return tokenUsesModel(withToken: token)
                }
            }
            if allKey.contains("borderColor") {
                let borderColorNode = tokenDict["borderColor"]
                if nodeIsEmpty(control: borderColor, node: borderColorNode as Any) {
                    if borderColorNodeUsesAction(control: borderColor, node: borderColorNode as Any) {
                        KMPrint("borderColor node user success")
                    } else {
                        return tokenUsesModel(withToken: token)
                    }
                } else {
                    return tokenUsesModel(withToken: token)
                }
            }
            if allKey.contains("borderRadius") {
                let borderRadiusNode = tokenDict["borderRadius"]
                if nodeIsEmpty(control: borderRadius, node: borderRadiusNode as Any) {
                    if borderRadiusNodeUsesAction(control: borderRadius, node: borderRadiusNode as Any) {
                        KMPrint("borderRadius node user success")
                    } else {
                        return tokenUsesModel(withToken: token)
                    }
                } else {
                    return tokenUsesModel(withToken: token)
                }
            }
            if allKey.contains("borderWidth") {
                let borderWidthNode = tokenDict["borderWidth"]
                if nodeIsEmpty(control: borderWidth, node: borderWidthNode as Any) {
                    if borderWidthNodeUsesAction(control: borderWidth, node: borderWidthNode as Any) {
                        KMPrint("borderWidth node user success")
                    } else {
                        return tokenUsesModel(withToken: token)
                    }
                } else {
                    return tokenUsesModel(withToken: token)
                }
            }
            if allKey.contains("boxShadow") {
                let boxShadowNode = tokenDict["boxShadow"]
                if nodeIsEmpty(control: boxShadow, node: boxShadowNode as Any) {
                    if boxShadowNodeUsesAction(control: boxShadow, node: boxShadowNode as Any) {
                        KMPrint("boxShadow node user success")
                    } else {
                        return tokenUsesModel(withToken: token)
                    }
                } else {
                    return tokenUsesModel(withToken: token)
                }
            }
            if allKey.contains("typography") {
                let typographyNode = tokenDict["typography"]
                if nodeIsEmpty(control: typography, node: typographyNode as Any) {
                    if typographyNodeUsesAction(control: typography, node: typographyNode as Any) {
                        KMPrint("typography node user success")
                    } else {
                        return tokenUsesModel(withToken: token)
                    }
                } else {
                    return tokenUsesModel(withToken: token)
                }
            }
        }
        return tokenUsesModel(withToken: token)
    }
        
    // MARK: height、width、spacing、verticalPaddin、horizontalPadding、paddingTop、paddingRight、paddingBottom、paddingLeft、itemSpacing
    
    func layoutConstraintNodeUsesAction(control: Any, node: Any) -> Bool  {
        if control is NSLayoutConstraint {
            (control as! NSLayoutConstraint).constant = (node as! String).stringToCGFloat()
            return true
        }
        return false
    }
                    
    // MARK: Private Methods
    
    func nodeIsEmpty(control: Any, node: Any) -> Bool {
        if (control is String) {
            return false
        } else {
            if (node is String) {
                if (node as! String == "") {
                    return false
                } else {
                    return true
                }
            } else if (node is [String : Any]) {
                return true
            }
        }
        return false
    }
}

extension KMDesignToken: KMJSONParserDelegate {
    func parser(_ parser: KMJSONParser, success responseObj: Any) {
        finalDict = responseObj as! [String : Any]
    }
}