//
//  KMDesignSelect.swift
//  PDF Master
//
//  Created by wanjun on 2023/2/22.
//

import Cocoa

@objc protocol KMSelectPopButtonDelegate: NSObjectProtocol {
    @objc optional func km_controlTextDidEndEditing(_ obj: KMDesignSelect)
    @objc optional func km_controlTextDidChange(_ obj: KMDesignSelect)
    @objc optional func km_SelectPopoverWillShow(_ obj: KMDesignSelect)
    func km_comboBoxSelectionDidChange(_ obj: KMDesignSelect)
}

@objc enum SelectType : Int {
    case PopButton = 0
    case Combox
}

class KMSelectCell: NSTextFieldCell {
    var borderThickness: CGFloat = 1
    var offset: CGFloat = 0.0

    override func drawingRect(forBounds theRect: NSRect) -> NSRect {
        var newRect:NSRect = super.drawingRect(forBounds: theRect)
        let textSize:NSSize = self.cellSize(forBounds: theRect)
//        let heightDelta:CGFloat = newRect.size.height - textSize.height
//        if heightDelta > 0 {
//            newRect.size.height = textSize.height
//            newRect.origin.y += heightDelta * 0.5
//        } else {
//            newRect.size.height = textSize.height
//            newRect.origin.y += heightDelta
//        }
        let originY = ((self.controlView?.bounds.size.height)! - textSize.height) / 2

        newRect.size.height = textSize.height
        newRect.origin.y += originY
        newRect.origin.x += offset
        newRect.size.width = theRect.width - offset*2
//        newRect.fill()
        return newRect
    }
    
    override func draw(withFrame cellFrame: NSRect, in controlView: NSView) {
        // Area that covers the NSTextField itself. That is the total height minus our custom border size.
        let interiorFrame = NSRect(x: 0, y: 0, width: cellFrame.width, height: cellFrame.height - borderThickness)

        let path = NSBezierPath()
        path.lineWidth = borderThickness
        // Line width is at the center of the line.
        path.move(to: NSPoint(x: 0, y: cellFrame.height))
        path.line(to: NSPoint(x: cellFrame.width, y: cellFrame.height))
        path.line(to: NSPoint(x: cellFrame.width, y: 0))
        path.line(to: NSPoint(x: 0, y: 0))
        NSColor.clear.setStroke()
        path.stroke()

        // Pass in area minus the border thickness in the height
        drawInterior(withFrame: interiorFrame, in: controlView)
    }
}

@objcMembers class KMDesignSelect: NSViewController {
    
    @IBOutlet weak var mainBox: KMBox!
    
    @IBOutlet weak var selectBox: NSBox!
    @IBOutlet weak var textField: NSTextField!
    @IBOutlet weak var imageView: NSImageView!

    @IBOutlet weak var horizontalPadding_spacing: NSLayoutConstraint!
    @IBOutlet weak var itemSpacing_spacing: NSLayoutConstraint!
    @IBOutlet weak var imageViewWidth_spacing: NSLayoutConstraint!
    @IBOutlet weak var imageViewHeight_spacing: NSLayoutConstraint!

    var imageWidth: Float = 12.0    // 图片宽度
    var imageHeight: Float = 12.0   // 图片高度
    var horizontalPadding: Float = 8.0
    var itemSpacing: Float = 8.0

    var borderColor: NSColor = .clear// 边框颜色
    var borderColor_hov: NSColor = .clear// 边框颜色
    var borderColor_focus: NSColor = .clear// 边框颜色
    var borderColor_disabled: NSColor = .clear// 边框颜色
    var borderColor_errordef: NSColor = .clear// 边框颜色
    var borderColor_errorfocus: NSColor = .clear// 边框颜色
    var cornerRadius: Float = 0.0// 边框圆角
    var cornerRadius_hov: Float = 0.0// 边框圆角
    var cornerRadius_focus: Float = 0.0// 边框圆角
    var cornerRadius_disabled: Float = 0.0// 边框圆角
    var cornerRadius_errordef: Float = 0.0// 边框圆角
    var cornerRadius_errorfocus: Float = 0.0// 边框圆角
    var borderWidth: Float = 1.0// 边框宽度
    var borderWidth_hov: Float = 1.0// 边框宽度
    var borderWidth_focus: Float = 1.0// 边框宽度
    var borderWidth_disabled: Float = 1.0// 边框宽度
    var borderWidth_errordef: Float = 1.0// 边框宽度
    var borderWidth_errorfocus: Float = 1.0// 边框宽度
    var background: NSColor = .clear// 背景颜色
    var background_hov: NSColor = .clear// 背景颜色
    var background_focus: NSColor = .clear// 背景颜色
    var background_disabled: NSColor = .clear// 背景颜色
    var background_errordef: NSColor = .clear// 背景颜色
    var background_errorfocus: NSColor = .clear// 背景颜色
    var textColor: NSColor = .black // 内容颜色
    var textColor_hov: NSColor = .black // 内容颜色
    var textColor_focus: NSColor = .black // 内容颜色
    var textColor_disabled: NSColor = .black // 内容颜色
    var textColor_errordef: NSColor = .black // 内容颜色
    var textColor_errorfocus: NSColor = .black // 内容颜色
    var lineHeight: CGFloat = 20.0 // 默认 内容行高
    var lineHeight_hov: CGFloat = 20.0 // 默认 内容行高
    var lineHeight_focus: CGFloat = 20.0 // 默认 内容行高
    var lineHeight_disabled: CGFloat = 20.0 // 默认 内容行高
    var lineHeight_errordef: CGFloat = 20.0 // 默认 内容行高
    var lineHeight_errorfocus: CGFloat = 20.0 // 默认 内容行高
    var font: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
    var font_hov: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
    var font_focus: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
    var font_disabled: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
    var font_errordef: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
    var font_errorfocus: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
    
    var textbg_errorfocus: NSColor = .clear // 正在输入高亮

    var _image: NSImage = NSImage(named: "icon_btn_arrow_gray_down_s_norm_false")!
    var _stringValue: String = ""// 内容
    var _toolTip: String = "" // 提示文字

    // button 通用属性
    var action: Selector?   // 点击事件
    var target: AnyObject? // 对象目标
    var _enabled: Bool = true // 是否可点击
    var _state: KMDesignTokenState = .Norm
    var canHover: Bool = true // 是否可悬浮
    var _isHidden: Bool = false // 是否隐藏
    var _editable: Bool = false // 是否允许编辑
    var _alignment: NSTextAlignment = .left //对齐
    var placeholderString: String = "" { // 预设文字
        didSet {
            self.textField.placeholderString = self.placeholderString
        }
    }
    var lineBreakMode: NSLineBreakMode = .byTruncatingTail //文字超出显示
    
    var buttonType: SelectType = .PopButton
    var items: [String] = []
    open weak var delete: KMSelectPopButtonDelegate?
    var _indexOfSelectedItem: Int = 0
    var _numberOfItems: Int = 0
    var disItems: [String] = []
    var isScrollPop = false

    var createFilePopover: NSPopover = NSPopover.init()
    var popoverBehavior: NSPopover.Behavior = .semitransient
    
    init(withType type: SelectType) {
        super.init(nibName: "KMDesignSelect", bundle: nil)
        self.buttonType = type
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
        
        textField.isSelectable = false
        
        if (buttonType == .PopButton) {
            self.mainBox.contentView = selectBox
            textField.delegate = self

            self.select(bg: "select.m.bg.norm", text: "select.m.mac-text.act")
            self.select(bg: "select.m.bg.hov", text: "select.m.mac-text.act", state: .Hov)
            self.select(bg: "select.m.bg.focus", text: "select.m.mac-text.act", state: .Focus)
            self.select(bg: "select.m.bg.dis", text: "select.m.mac-text.dis", state: .Disabled)
            self.select(bg: "select.m.bg.error-def", text: "select.m.mac-text.act", state: .Error_def)
            self.select(bg: "select.m.bg.error-focus", text: "select.m.mac-text.act", textbg: "select.m.bg-text", state: .Error_focus)
        } else if (buttonType == .Combox) {
            self.mainBox.contentView = selectBox
            textField.delegate = self
            
            self.select(bg: "select.m.bg.norm", text: "select.m.mac-text.act")
            self.select(bg: "select.m.bg.hov", text: "select.m.mac-text.act", state: .Hov)
            self.select(bg: "select.m.bg.focus", text: "select.m.mac-text.act", state: .Focus)
            self.select(bg: "select.m.bg.dis", text: "select.m.mac-text.dis", state: .Disabled)
            self.select(bg: "select.m.bg.error-def", text: "select.m.mac-text.act", state: .Error_def)
            self.select(bg: "select.m.bg.error-focus", text: "select.m.mac-text.act", textbg: "select.m.bg-text", state: .Error_focus)
        }
                
        self.mainBox.canHover = true
        self.mainBox.canClick = true
        self.mainBox.downCallback = { [unowned self](downEntered, mouseBox, event) -> Void in
            if self.enabled {
                if downEntered {
                    self.canHover = false
                    self.mainBoxAction(mouseBox)
                }
            }
        }
        self.mainBox.moveCallback = { [unowned self](mouseEntered: Bool, mouseBox: KMBox) -> Void in
            if !self.createFilePopover.isShown && self.canHover && (self.state != .Disabled) {
                self.canHover = true
                if mouseEntered {
                    self.state = .Hov
                } else {
                    self.state = .Norm
                }
                self.updateUI()
            }
        }
        
        createFilePopover.delegate = self
    }
    
    // MARK: Get、Set
    
    var stringValue: String {
        get {
            return _stringValue
        }
        set {
            _stringValue = newValue
            
            let paragraphStyle = NSMutableParagraphStyle()
            if (state == .Norm) {
                paragraphStyle.lineSpacing = lineHeight
            } else if (state == .Hov) {
                paragraphStyle.lineSpacing = lineHeight_hov
            } else if (state == .Focus) {
                paragraphStyle.lineSpacing = lineHeight_focus
            } else if (state == .Disabled) {
                paragraphStyle.lineSpacing = lineHeight_disabled
            } else if (state == .Error_def) {
                paragraphStyle.lineSpacing = lineHeight_errordef
            } else if (state == .Error_focus) {
                paragraphStyle.lineSpacing = lineHeight_errorfocus
            }
            paragraphStyle.lineBreakMode = .byTruncatingTail
            paragraphStyle.alignment = alignment
            textField.attributedStringValue = NSAttributedString(string: _stringValue, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle])
        }
    }
    
    var alert: Bool = false {
        didSet {
            updateUI()
        }
    }
    
    var enabled: Bool {
        get {
            return _enabled
        }
        set {
            _enabled = newValue
            if _enabled {
                _state = .Norm
            } else {
                _state = .Disabled
            }
            updateUI()
        }
    }
    var state: KMDesignTokenState {
        get {
            return _state
        }
        set {
            _state = newValue
            updateUI()
        }
    }
    var isHidden: Bool {
        get {
            return _isHidden
        }
        set {
            _isHidden = newValue
            
            self.view.isHidden = _isHidden
        }
    }
    var editable: Bool {
        get {
            return _editable
        }
        set {
            _editable = newValue
            
            textField.isEditable = _editable
        }
    }
    
    var indexOfSelectedItem: Int {
        get {
            return _indexOfSelectedItem
        }
        set {
            _indexOfSelectedItem = newValue
        }
    }
    
    var numberOfItems: Int {
        get {
            return items.count
        }
    }
    var image: NSImage {
        get {
            return _image
        }
        set {
            _image = newValue
            
            imageView.image = _image
        }
    }
    
    var toolTip: String {
        get {
            return _toolTip
        }
        set {
            _toolTip = newValue
            if _toolTip != "" {
                mainBox.toolTip = _toolTip
            }
        }
    }
    
    var alignment: NSTextAlignment {
        get {
            return _alignment
        }
        set {
            _alignment = newValue
            
            textField.alignment = alignment
        }
    }
    
    // MARK: Private Methods

    func updateUI() -> Void {
        if (state == .Norm) {
            selectBox.fillColor = background
            selectBox.borderWidth = CGFloat(borderWidth)
            selectBox.cornerRadius = CGFloat(cornerRadius)
            selectBox.borderColor = borderColor
            textField.textColor = textColor
            textField.font = font
            imageView.image = NSImage(named: "KMImageNameSelectNormal")
        } else if (state == .Hov) {
            selectBox.fillColor = background_hov
            selectBox.borderWidth = CGFloat(borderWidth_hov)
            selectBox.cornerRadius = CGFloat(cornerRadius_hov)
            selectBox.borderColor = borderColor_hov
            textField.textColor = textColor_hov
            textField.font = font_hov
            imageView.image = NSImage(named: "KMImageNameSelectHover")
        } else if (state == .Focus) {
            selectBox.fillColor = background_focus
            selectBox.borderWidth = CGFloat(borderWidth_focus)
            selectBox.cornerRadius = CGFloat(cornerRadius_focus)
            selectBox.borderColor = borderColor_focus
            textField.textColor = textColor_focus
            textField.font = font_focus
            imageView.image = NSImage(named: "KMImageNameSelectFocus")
        } else if (state == .Disabled) {
            selectBox.fillColor = background_disabled
            selectBox.borderWidth = CGFloat(borderWidth_disabled)
            selectBox.cornerRadius = CGFloat(cornerRadius_disabled)
            selectBox.borderColor = borderColor_disabled
            textField.textColor = textColor_disabled
            textField.font = font_disabled
            imageView.image = NSImage(named: "KMImageNameSelectDisable")
        } else if (state == .Error_def) {
            selectBox.fillColor = background_errordef
            selectBox.borderWidth = CGFloat(borderWidth_errordef)
            selectBox.cornerRadius = CGFloat(cornerRadius_errordef)
            selectBox.borderColor = borderColor_errordef
            textField.textColor = textColor_errordef
            textField.font = font_errordef
            imageView.image = NSImage(named: "KMImageNameSelectNormal")
        } else if (state == .Error_focus) {
            selectBox.fillColor = background_errorfocus
            selectBox.borderWidth = CGFloat(borderWidth_errorfocus)
            selectBox.cornerRadius = CGFloat(cornerRadius_errorfocus)
            selectBox.borderColor = borderColor_errorfocus
            textField.textColor = textColor_errorfocus
            textField.font = font_errorfocus
            imageView.image = NSImage(named: "KMImageNameSelectNormal")
        }
        
        if alert == true {
            selectBox.borderColor = NSColor.km_init(hex: "#F3465B")
        } else {
            selectBox.borderColor = selectBox.borderColor
        }
        
        imageViewWidth_spacing.constant = CGFloat(imageWidth)
        imageViewHeight_spacing.constant = CGFloat(imageHeight)
        horizontalPadding_spacing.constant = CGFloat(horizontalPadding)
        itemSpacing_spacing.constant = CGFloat(itemSpacing)

        textField.isEditable = editable
//        textField.placeholderString = placeholderString
        textField.lineBreakMode = lineBreakMode
    }
    
    func removeAllItems() {
        items = []
    }
    
    func addItems(withObjectValues objects: [String]) {
        items = objects
    }
    
    func selectItem(at index: Int) {
        if items.count > 0 && index < items.count {
            stringValue = items[index]
            self.indexOfSelectedItem = index
        }
    }
    
    // MARK: Action
    
    func mainBoxAction(_ sender: Any) -> Void {
        self.delete?.km_SelectPopoverWillShow?(self)
        
        if createFilePopover.isShown {
            createFilePopover.close()
        } else {
            var vc: KMHomePopViewController?
            if (self.isScrollPop) {
                vc = KMScrollPopViewController()
            } else {
                vc = KMHomePopViewController()
            }
            let _ = vc?.initWithPopViewDataArr(items)

            createFilePopover.contentViewController = vc
            if (self.stringValue.isEmpty == false) {
                vc?.selectedItems = [self.stringValue]
            }
            createFilePopover.animates = true
            createFilePopover.behavior = self.popoverBehavior
            createFilePopover.setValue(true, forKey: "shouldHideAnchor")
            createFilePopover.show(relativeTo: CGRect(x: view.bounds.origin.x, y: 10, width: view.bounds.size.width, height: view.bounds.size.height), of: view, preferredEdge: .minY)
            var width = mainBox.frame.width
            for i in items {
                let w = i.getTextRectSize(font: .systemFont(ofSize: 14.0), size: CGSize(width: CGFloat(MAXFLOAT), height: 32.0)).width+12*2
                if width < w {
                    width = w
                }
            }
            
            vc?.customBoxWidthLayoutConstraint.constant = width
            vc?.downCallback = { [unowned self] (downEntered: Bool, count: String) -> Void in
                if downEntered {
                    self.stringValue = count
                    
                    let current = self.items.firstIndex(of: count) ?? 0
                    self.indexOfSelectedItem = current
                    self.delete?.km_comboBoxSelectionDidChange(self)
                    
                    self.updateUI()
                    
                    self.createFilePopover.close()
                }
            }
        }
    }
}

extension KMDesignSelect: NSTextFieldDelegate {
    func controlTextDidChange(_ obj: Notification) {
        let textfield = obj.object as! NSTextField
        self.stringValue = textfield.stringValue

        self.delete?.km_controlTextDidChange?(self)
    }
    
    func controlTextDidEndEditing(_ obj: Notification) {
        let textfield = obj.object as! NSTextField
        
        self.stringValue = textfield.stringValue
        
        self.delete?.km_controlTextDidEndEditing?(self)
    }
}

extension KMDesignSelect: NSPopoverDelegate {
    func popoverWillShow(_ notification: Notification) {
        let popover = notification.object as! NSPopover
        if (createFilePopover == popover) {
            self.state = .Focus
            self.canHover = false
            
            let vc = createFilePopover.contentViewController! as! KMHomePopViewController
            vc.disItems = disItems
        }
    }
    
    func popoverWillClose(_ notification: Notification) {
        let popover = notification.object as! NSPopover
        if (createFilePopover == popover) {
            self.state = .Norm
            self.canHover = true
        }
    }
}