//
//  KMBatchTableCellView.swift
//  PDF Reader Pro
//
//  Created by kdanmobile on 2023/10/27.
//

import Cocoa

typealias batchTableCellComboboxMouseDownCallback = (_ mouseDown: Bool) -> ()
typealias batchTableCellRemoveFileCallBack = (_ file: KMBatchOperateFile) -> ()

@objc enum KMBatchTableCellViewType: Int {
    case Size = 0
    case PageRange
    case FileName
    case Status
    case DPI
    case Dimensions
}

class KMBatchTableCellCombobox: KMComboBox{
    var mouseDownCallback: batchTableCellComboboxMouseDownCallback?
    override func mouseDown(with event: NSEvent) {
        super.mouseDown(with: event)
        if (self.mouseDownCallback != nil) {
            self.mouseDownCallback!(true)
        }
    }
}

class KMBatchTableCellView: NSTableCellView,NSComboBoxDelegate{
    var removeFileCallBack: batchTableCellRemoveFileCallBack?
    var pageRangeCombobox: KMBatchTableCellCombobox?
    var errorTextField: NSTextField?
    var statusView: NSView?
    var removeButton: KMButton?
    var progressIndicator: NSProgressIndicator?
    var type: KMBatchTableCellViewType?
    var file: KMBatchOperateFile?
    var DPIComboBox: KMBatchTableCellCombobox?
    var indicateImageView: NSImageView?
    var comboBoxContent: String?
    
    deinit {
        DistributedNotificationCenter.default().removeObserver(self)
    }
    
    convenience init(type: KMBatchTableCellViewType) {
        self.init()
        switch type {
        case .Size:
            configuUIForSize()
        case .Dimensions:
            configuUIForSize()
        case .PageRange:
            configuUIForPageRange()
        case .FileName:
            configuUIForFileName()
        case .Status:
            configuUIForStatus()
        case .DPI:
            configuUIForDPI()
        default:
            break
        }
        DistributedNotificationCenter.default().addObserver(self, selector: #selector(themeChanged(notification:)), name: NSNotification.Name("AppleInterfaceThemeChangedNotification"), object: nil)
        self.type = type
    }
    func configuUIForSize() {
        let tf = NSTextField(frame: .zero)
        self.textField = tf
        self.textField?.isBordered = false
        self.textField?.drawsBackground = true
        self.textField?.backgroundColor = NSColor.clear
        self.textField?.isEditable = false
        self.addSubview(self.textField!)
        self.textField?.mas_makeConstraints({ make in
            make?.top.equalTo()(self)?.offset()(13)
            make?.left.equalTo()(self)
            
        })
        self.textField?.textColor = KMAppearance.Layout.h0Color()
        self.textField?.font = NSFont.systemFont(ofSize: 12)
    }
    func configuUIForPageRange() {
        self.pageRangeCombobox = KMBatchTableCellCombobox(frame: .zero)
        self.pageRangeCombobox?.focusRingType = .none
        self.pageRangeCombobox?.type = .none
        self.pageRangeCombobox?.wantsLayer = true
        self.pageRangeCombobox?.layer?.backgroundColor = KMAppearance.Layout.l1Color().cgColor
        self.pageRangeCombobox?.layer?.borderWidth = 1.0
        self.pageRangeCombobox?.layer?.borderColor = KMAppearance.Interactive.s0Color().cgColor
        self.pageRangeCombobox?.layer?.cornerRadius = 1.0
        self.pageRangeCombobox?.backgroundColor = KMAppearance.Layout.l1Color()
        self.addSubview(self.pageRangeCombobox!)
        self.pageRangeCombobox?.mas_makeConstraints({ make in
            make?.left.equalTo()(self)
            make?.right.equalTo()(self)?.offset()(-20)
            make?.top.equalTo()(self)?.offset()(10)
        })
        let choiceArray = [
            "  \(NSLocalizedString("All Pages", comment: ""))",
            "  \(NSLocalizedString("Odd Pages Only", comment: ""))",
            "  \(NSLocalizedString("Even Pages Only", comment: ""))",
            "  \(NSLocalizedString("e.g. 1,3-5,10", comment: ""))"
        ]
        self.pageRangeCombobox?.addItems(withObjectValues: choiceArray)
        let placeholderString = "  \(NSLocalizedString("e.g. 1,3-5,10", comment: ""))"
        //        self.pageRangeCombobox!.cell.placeholderString = placeholderString
        self.pageRangeCombobox?.selectItem(at: 0)
        self.pageRangeCombobox?.isEditable = false
        self.pageRangeCombobox?.delegate = self
        self.comboBoxContent = placeholderString
        
        self.updateViewColor()
        self.pageRangeCombobox?.mouseDownCallback = { [weak self] mouseDown in
            let itemIdex = self?.pageRangeCombobox?.indexOfSelectedItem ?? 0
            if itemIdex == 3 {//KMBatchOperatePageChoice.Input
                if self?.comboBoxContent == placeholderString {
                    self?.pageRangeCombobox?.stringValue = ""
                } else {
                    self?.pageRangeCombobox?.stringValue = (self?.comboBoxContent) ?? ""
                }
            }
        }
    }
    func configuUIForFileName() {
        var tf = NSTextField(frame: .zero)
        self.textField = tf
        self.textField?.isBordered = false
        self.textField?.drawsBackground = true
        self.textField?.backgroundColor = NSColor.clear
        self.textField?.isEditable = false
        self.textField?.maximumNumberOfLines = 1
        self.textField?.lineBreakMode = .byTruncatingMiddle
        self.addSubview(self.textField!)
        self.textField?.mas_makeConstraints({ make in
            make?.top.equalTo()(self)?.offset()(13)
            make?.left.equalTo()(self)
            make?.right.equalTo()(self)?.offset()(-10)
        })
        self.textField?.font = NSFont.systemFont(ofSize: 12)
        self.textField?.textColor = KMAppearance.Layout.h0Color()
        self.errorTextField = NSTextField(frame: .zero)
        self.errorTextField?.isBordered = false
        self.errorTextField?.drawsBackground = true
        self.errorTextField?.backgroundColor = NSColor.clear
        self.errorTextField?.isEditable = false
        self.errorTextField?.font = NSFont.systemFont(ofSize: 12)
        self.errorTextField?.textColor = KMAppearance.Status.errColor()
        self.errorTextField?.lineBreakMode = .byTruncatingMiddle
        self.addSubview(self.errorTextField!)
        self.errorTextField?.mas_makeConstraints({ make in
            make?.top.equalTo()(self.textField?.mas_bottom)
            make?.left.equalTo()(self)
            make?.bottom.equalTo()(self)?.offset()(-11)
            make?.right.equalTo()(self.mas_right)
        })
    }
    func configuUIForStatus() {
        self.statusView = NSView(frame: .zero)
        self.statusView?.wantsLayer = true
        self.addSubview(self.statusView!)
        self.statusView?.mas_makeConstraints({ make in
            make?.left.equalTo()(self)
            make?.top.equalTo()(self)?.offset()(12)
            make?.width.equalTo()(16)
            make?.height.equalTo()(16)
        })
        self.indicateImageView = NSImageView(frame: .zero)
        self.statusView?.addSubview(self.indicateImageView!)
        
        self.indicateImageView?.mas_makeConstraints({ make in
            make?.edges.equalTo()(self.statusView)
        })
        self.progressIndicator = NSProgressIndicator(frame: .zero)
        self.statusView?.addSubview(self.progressIndicator!)
        
        self.progressIndicator?.mas_makeConstraints({ make in
            make?.edges.equalTo()(self.statusView)
        })
        self.progressIndicator?.maxValue = 1.0
        self.progressIndicator?.minValue = 0
        self.progressIndicator?.style = .spinning
        self.progressIndicator?.controlSize = .small
        self.removeButton = KMButton(image: NSImage(named: KMImageNameUXIconBtnCloseNor)!, target: self, action: #selector(deleteFile(sender:)))
        self.removeButton?.isBordered = false
        self.removeButton?.isHidden = true
        self.addSubview(self.removeButton!)
        self.removeButton?.mas_makeConstraints({ make in
            //            make?.left.equalTo()(self)?.offset()(10)
            make?.centerY.equalTo()(self)
            make?.right.equalTo()(self)?.offset()(0)
            make?.width.equalTo()(20)
            make?.height.equalTo()(20)
        })
        self.removeButton!.mouseMoveCallback = { [weak self] mouseEntered in
            if mouseEntered {
                self?.removeButton?.image = NSImage(named: KMImageNameUXIconBtnCloseHov)
            } else {
                self?.removeButton?.image = NSImage(named: KMImageNameUXIconBtnCloseNor)
            }
        }
    }
    func configuUIForDPI() {
        self.DPIComboBox = KMBatchTableCellCombobox(frame: .zero)
        self.DPIComboBox?.focusRingType = .none
        self.DPIComboBox?.type = .none
        self.DPIComboBox?.wantsLayer = true
        self.DPIComboBox?.layer?.backgroundColor = KMAppearance.Layout.l1Color().cgColor
        self.DPIComboBox?.layer?.borderWidth = 1.0
        self.DPIComboBox?.layer?.borderColor = KMAppearance.Interactive.s0Color().cgColor
        self.DPIComboBox?.layer?.cornerRadius = 1.0
        self.DPIComboBox?.backgroundColor = KMAppearance.Layout.l1Color()
        self.addSubview(self.DPIComboBox!)
        
        let DPIArray = ["50 dpi", "72 dpi", "96 dpi", "150 dpi", "300 dpi", "600 dpi"]
        self.DPIComboBox?.addItems(withObjectValues: DPIArray)
        self.DPIComboBox?.selectItem(at: 0)
        self.DPIComboBox?.isEditable = false
     
        self.DPIComboBox?.delegate = self
        self.DPIComboBox?.mas_makeConstraints({ make in
            make?.left.equalTo()(self)
            make?.right.equalTo()(self)?.offset()(-20)
            make?.top.equalTo()(self)?.offset()(11)
            make?.bottom.equalTo()(self)?.offset()(-11)
        })
    }
    @objc func themeChanged(notification: NSNotification) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
            self.updateViewColor()
        }
    }
    @objc func deleteFile(sender: Any) {
        if (self.removeFileCallBack != nil) {
            self.removeFileCallBack!(self.file!)
        }
    }
    func updateViewColor() {
        if KMAppearance.isDarkMode() {
            self.DPIComboBox?.backgroundColor = NSColor(red: 0.224, green: 0.235, blue: 0.243, alpha: 1)
            self.DPIComboBox?.layer!.backgroundColor = NSColor(red: 0.224, green: 0.235, blue: 0.243, alpha: 1).cgColor
            self.DPIComboBox?.layer!.borderColor = NSColor(red: 0.337, green: 0.345, blue: 0.353, alpha: 1).cgColor
            self.pageRangeCombobox?.backgroundColor = NSColor(red: 0.224, green: 0.235, blue: 0.243, alpha: 1)
            self.pageRangeCombobox?.layer!.backgroundColor = NSColor(red: 0.224, green: 0.235, blue: 0.243, alpha: 1).cgColor
            self.pageRangeCombobox?.layer!.borderColor = NSColor(red: 0.337, green: 0.345, blue: 0.353, alpha: 1).cgColor
        } else {
            self.DPIComboBox?.backgroundColor = NSColor.white
            self.DPIComboBox?.layer!.backgroundColor = NSColor.white.cgColor
            self.DPIComboBox?.layer!.borderColor = NSColor(red: 0.855, green: 0.859, blue: 0.871, alpha: 1).cgColor
            self.pageRangeCombobox?.backgroundColor = NSColor.white
            self.pageRangeCombobox?.layer!.backgroundColor = NSColor.white.cgColor
            self.pageRangeCombobox?.layer!.borderColor = NSColor(red: 0.855, green: 0.859, blue: 0.871, alpha: 1).cgColor
        }
    }
    func updateInterface(_ file: KMBatchOperateFile) {
        self.file = file
        if self.type == .Size {
            self.textField?.stringValue = file.sizeString
        } else if self.type == .FileName {
            if (file.error != nil) {
                self.errorTextField?.stringValue = file.error!.localizedDescription
                self.errorTextField?.isHidden = false
            } else {
                self.errorTextField?.isHidden = true
            }
            self.textField?.stringValue = file.filePath.lastPathComponent
        } else if self.type == .PageRange {
            self.pageRangeCombobox?.isEnabled = self.file!.status != .processing
            self.pageRangeCombobox?.delegate = nil
            self.pageRangeCombobox?.selectItem(at: file.currentOperateInfo?.pageChoice.rawValue ?? 0)
            self.pageRangeCombobox?.isEditable = false
            if file.currentOperateInfo?.pageChoice == .Input {
                self.pageRangeCombobox?.isEditable = true
                self.pageRangeCombobox?.stringValue = file.currentOperateInfo?.pageRangeString ?? ""
            }
            self.pageRangeCombobox?.delegate = self
        } else if self.type == .Status {
            if file.status == .Waiting {
                self.indicateImageView?.isHidden = false
                self.progressIndicator?.isHidden = true
                
                self.indicateImageView?.image = NSImage(named: KMImageNameUXIconProgressWaiting)
            } else if file.status == .Success {
                self.indicateImageView?.isHidden = false
                self.progressIndicator?.isHidden = true
                self.indicateImageView?.image = NSImage(named: "KMImageNameUXIconProgressComplete")
            } else if file.status == .Failed {
                self.indicateImageView?.isHidden = false
                self.progressIndicator?.isHidden = true
                self.indicateImageView?.image = NSImage(named: "KMImageNameUXIconProgressFailure")
            } else if file.status == .processing {
                self.indicateImageView?.isHidden = true
                self.progressIndicator?.isHidden = false
                self.progressIndicator?.startAnimation(nil)
            } else {
                self.indicateImageView?.isHidden = false
                self.progressIndicator?.isHidden = true
                
                self.indicateImageView?.image = NSImage(named: KMImageNameUXIconProgressWaiting)
            }
        } else if self.type == .DPI {
            switch self.file?.dpi {
            case 50:
                self.DPIComboBox?.selectItem(at: 0)
            case 72:
                self.DPIComboBox?.selectItem(at: 1)
            case 96:
                self.DPIComboBox?.selectItem(at: 2)
            case 150:
                self.DPIComboBox?.selectItem(at: 3)
            case 300:
                self.DPIComboBox?.selectItem(at: 4)
            case 600:
                self.DPIComboBox?.selectItem(at: 5)
            default:
                break
            }
            self.DPIComboBox?.isEnabled = self.file?.status != .processing
        } else if self.type == .Dimensions {
            
        }
    }
    func updateInterface( file: KMBatchOperateFile, progress: Float) {
        updateInterface(file)
        if progress > 0 && file.status == .processing {
            self.progressIndicator?.doubleValue = Double(progress)
            self.progressIndicator?.startAnimation(nil)
            self.progressIndicator?.isIndeterminate = false
        }
    }
    func updateInterface(isProgress progress: Int) {
        if progress == -1 {
            self.indicateImageView?.isHidden = false
            self.progressIndicator?.isHidden = true
            self.indicateImageView?.image = NSImage(named: "KMImageNameUXIconProgressFailure")
        } else if progress == 0 {
            self.indicateImageView?.isHidden = false
            self.progressIndicator?.isHidden = true
            self.indicateImageView?.image = NSImage(named: KMImageNameUXIconProgressWaiting)
        } else {
            self.indicateImageView?.isHidden = false
            self.progressIndicator?.isHidden = true
            self.indicateImageView?.image = NSImage(named: "KMImageNameUXIconProgressComplete")
        }
    }
    func controlTextDidEndEditing(_ obj: Notification) {
        if let data = self.pageRangeCombobox?.isEqual(obj.object), data {
            self.file?.currentOperateInfo?.pageRangeString = self.pageRangeCombobox!.stringValue
            if self.file?.currentOperateInfo?.pagesArray == nil {
                let alert = NSAlert()
                alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
                alert.alertStyle = .critical
                alert.messageText = self.file!.filePath.lastPathComponent.lastPathComponent + NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "")
                alert.beginSheetModal(for: self.window!, completionHandler: nil)
                self.pageRangeCombobox?.selectItem(at: 0)
                self.file?.currentOperateInfo?.pageChoice = .All
            }
        }
    }
    func controlTextDidChange(_ obj: Notification) {
        let comboBox: NSComboBox = obj.object as! NSComboBox;
        if comboBox.isEqual(self.pageRangeCombobox) {
            self.comboBoxContent = comboBox.stringValue;
        }
    }
    
    func comboBoxSelectionDidChange(_ notification: Notification) {
        if notification.object as? NSComboBox == self.pageRangeCombobox {
            self.pageRangeCombobox?.delegate = nil
            self.file?.currentOperateInfo!.pageChoice = self.tromsformPageChoice(index: self.pageRangeCombobox?.indexOfSelectedItem ?? 0)
            if self.pageRangeCombobox?.indexOfSelectedItem == KMBatchOperatePageChoice.Input.rawValue {
                self.pageRangeCombobox?.isEditable = true
                self.pageRangeCombobox?.isSelectable = true
                self.window?.makeFirstResponder(self.pageRangeCombobox)
            } else {
                self.pageRangeCombobox?.resignFirstResponder()
                self.pageRangeCombobox?.isEditable = false
                self.pageRangeCombobox?.isSelectable = false
            }
            self.pageRangeCombobox?.delegate = self
        } else if notification.object as? NSComboBox == self.DPIComboBox {
            switch self.DPIComboBox?.indexOfSelectedItem
            {
            case 0:
                self.file?.currentConvertParameter?.dpi = 50
            case 1:
                self.file?.currentConvertParameter?.dpi = 72
            case 2:
                self.file?.currentConvertParameter?.dpi = 96
            case 3:
                self.file?.currentConvertParameter?.dpi = 150
            case 4:
                self.file?.currentConvertParameter?.dpi = 300
            case 5:
                self.file?.currentConvertParameter?.dpi = 600
            default:
                break
            }
        }
    }
    func tromsformPageChoice(index: Int) -> KMBatchOperatePageChoice {
        var pageChoice: KMBatchOperatePageChoice?
        switch index {
        case 0:
            pageChoice = .All
        case 1:
            pageChoice = .Odd
        case 2:
            pageChoice = .Even
        case 3:
            pageChoice = .Input
        default:
            pageChoice = .All
        }
        return pageChoice ?? .All
    }
    
}