//
//  KMTextWithIconCell.swift
//  PDF Reader Pro
//
//  Created by lizhe on 2024/2/21.
//

import Cocoa

let SKTextWithIconStringKey = "string"
let SKTextWithIconImageKey = "image"
let BORDER_BETWEEN_EDGE_AND_IMAGE: CGFloat = 2.0
let BORDER_BETWEEN_IMAGE_AND_TEXT: CGFloat = 2.0
let IMAGE_OFFSET: CGFloat = 1.0

class KMTextWithIconCell: NSTextFieldCell {
    var imageCell: NSImageCell = NSImageCell()
    
    override init(textCell string: String) {
        super.init(textCell: string)
        commonInit()
    }
    
    required init(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() {
        imageCell.imageScaling = .scaleProportionallyUpOrDown
//        if formatter == nil {
//            formatter = DictionaryFormatter(key: SKTextWithIconStringKey)
//        }
    }
    
    override func cellSize(forBounds rect: NSRect) -> NSSize {
        var cellSize = super.cellSize(forBounds: rect)
        cellSize.width += cellSize.height - 1 + BORDER_BETWEEN_EDGE_AND_IMAGE + BORDER_BETWEEN_IMAGE_AND_TEXT
        cellSize.width = min(cellSize.width, rect.width)
        return cellSize
    }
    
    private func textRect(forBounds rect: NSRect) -> NSRect {
        return KMShrinkRect(rect, NSHeight(rect) - 1 + BORDER_BETWEEN_EDGE_AND_IMAGE + BORDER_BETWEEN_IMAGE_AND_TEXT, .minX)
    }
    
    private func iconRect(forBounds rect: NSRect) -> NSRect {
        return KMSliceRect(KMShrinkRect(rect, BORDER_BETWEEN_EDGE_AND_IMAGE, .minX), NSHeight(rect) - 1, .minX)
    }
    
    override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
        // let super draw the text
        let textRect = textRect(forBounds: cellFrame)
        super.drawInterior(withFrame: textRect, in: controlView)
        
        // Draw the image
        var imageRect = iconRect(forBounds: cellFrame)
        imageRect = KMCenterRectVertically(rect: imageRect, height: NSWidth(imageRect), offset: IMAGE_OFFSET, flipped: controlView.isFlipped)
        imageCell.drawInterior(withFrame: imageRect, in: controlView)
    }
    
    override func edit(withFrame cellFrame: NSRect, in controlView: NSView, editor textObj: NSText, delegate anObject: Any?, event: NSEvent?) {
        super.edit(withFrame: textRect(forBounds: cellFrame), in: controlView, editor: textObj, delegate: anObject, event: event)
    }
    
    override func select(withFrame cellFrame: NSRect, in controlView: NSView, editor textObj: NSText, delegate anObject: Any?, start selStart: Int, length selLength: Int) {
        super.select(withFrame: textRect(forBounds: cellFrame), in: controlView, editor: textObj, delegate: anObject, start: selStart, length: selLength)
    }
    
    override func hitTest(for event: NSEvent, in rect: NSRect, of controlView: NSView) -> NSCell.HitResult {
        let textRect = textRect(forBounds: rect)
        let mouseLoc = event.location(inPDFListView: controlView)
        var hit: NSCell.HitResult = []
        if NSMouseInRect(mouseLoc, textRect, controlView.isFlipped) {
            hit = super.hitTest(for: event, in: textRect, of: controlView)
        } else if NSMouseInRect(mouseLoc, iconRect(forBounds: rect), controlView.isFlipped) {
            hit = .contentArea
        }
        return hit
    }
    
    override var objectValue: Any? {
        didSet {
            if let obj = objectValue as? NSDictionary {
//                imageCell.image = obj[SKTextWithIconImageKey] as? NSImage
                self.stringValue = obj[SKTextWithIconStringKey] as! String
            }
        }
    }
    
    var icon: NSImage? {
        return imageCell.image
    }
}

extension KMTextWithIconCell {
    func KMSliceRect(_ rect: NSRect, _ amount: CGFloat, _ edge: NSRectEdge) -> NSRect {
        var rect = rect
        var ignored = NSRect.zero
        NSDivideRect(rect, &rect, &ignored, amount, edge);
        return rect
    }

    func KMShrinkRect(_ rect: NSRect, _ amount: CGFloat, _ edge: NSRectEdge) -> NSRect {
        var rect = rect
        var ignored = NSRect.zero
        NSDivideRect(rect, &ignored, &rect, amount, edge);
        return rect
    }
    
    func KMCenterRectVertically(rect: NSRect, height: CGFloat , offset: CGFloat, flipped: Bool) -> NSRect {
        var rect = rect
        rect.origin.y += 0.5 * (NSHeight(rect) - height);
        rect.origin.y = flipped ? ceil(rect.origin.y) - offset  : floor(rect.origin.y) + offset;
        rect.size.height = height;
        return rect;
    }
}