//
//  KMToolbarCustomViewController.swift
//  PDF Reader Pro
//
//  Created by tangchao on 2023/10/26.
//

import Cocoa

private let KMPasteboardTypeAllowedIndexSet: NSPasteboard.PasteboardType = NSPasteboard.PasteboardType(rawValue: "KMPasteboardTypeAllowedIndexSet")
private let KMPasteboardTypeDefaultIndexSet: NSPasteboard.PasteboardType = NSPasteboard.PasteboardType(rawValue: "KMPasteboardTypeDefaultIndexSet")

private let KMToolbarImageToPDFItemIdentifier = "KMToolbarImageToPDFItemIdentifier"
private let KMToolbarRotateRightItemIdentifier = "KMToolbarRotateRightItemIdentifier"

private let KMToolbarRotateLeftItemIdentifier = "KMToolbarRotateLeftItemIdentifier"
private let KMToolbarPageBreaksItemIdentifier = "KMToolbarPageBreaksItemIdentifier"

private let KMToolbarViewModeItemIdentifier = "KMToolbarViewModeItemIdentifier"
private let KMToolbarDisplayModeItemIdentifier = "KMToolbarDisplayModeItemIdentifier"

private let KMToolbarSpaceItemIdentifier = "KMToolbarSpaceItemIdentifier"
//private let KMImageNameToolbarSpace = "KMImageNameToolbarSpace"
private let KMToolbarFormAlignmentIdentifier = "KMToolbarFormAlignmentIdentifier"

let KMToolbarCustomChangeNotification: Notification.Name = Notification.Name(rawValue: "KMToolbarCustomChangeNotification")

class KMToolbarCellView: NSTableCellView {
    @IBOutlet weak var tickImageView: NSImageView!
}

class KMToolbarCustomViewController: NSViewController {
    
    @IBOutlet weak var titleLabel: NSTextField!
    @IBOutlet weak var leftLabel: NSTextField!
    @IBOutlet weak var rightLabel: NSTextField!
    @IBOutlet weak var subTitleLabel: NSTextField!
    
    @IBOutlet weak var okButton: NSButton!
    @IBOutlet weak var cancelButton: NSButton!
    @IBOutlet weak var resetButton: NSButton!
    @IBOutlet weak var addButton: NSButton!
    @IBOutlet weak var removeButton: NSButton!
    
    @IBOutlet weak var allowedItemsTableView: NSTableView!
    @IBOutlet weak var defaultItemsTableView: NSTableView!
    
    private var _allowedItems: [String] = []
    private var _defaultItems: [String] = []
    
    weak var toolbar: KMToolbarView?
    
    override func loadView() {
        super.loadView()
        
        self.titleLabel.stringValue = KMLocalizedString("Customize Toolbar", nil)
        self.subTitleLabel.stringValue = String(format: "%@", KMLocalizedString("Drag-and-drop tools to change their order", nil))
        self.leftLabel.stringValue = KMLocalizedString("Choose tools to add:", nil)
        self.rightLabel.stringValue = KMLocalizedString("Tools to show in Toolbar:", nil)

        self.okButton.title = KMLocalizedString("Done", nil)
        self.cancelButton.title = KMLocalizedString("Cancel", nil)
        self.resetButton.title = KMLocalizedString("Reset", nil)
        self.resetButton.toolTip = KMLocalizedString("Reset Toolbars", nil)
        
        self.addButton.title = String(format: "%@  >>", KMLocalizedString("Add", nil))
        self.addButton.toolTip = KMLocalizedString("Add to Toolbar", nil)
        
        self.removeButton.title = String(format: "<<  %@", KMLocalizedString("Remove", nil))
        self.removeButton.toolTip = KMLocalizedString("Remove from Toolbar", nil)
        
        var color = NSColor(red: 51.0/255.0, green: 51.0/255.0, blue: 51.0/255.0, alpha: 1.0)
        if (KMAppearance.isSupportNewColor()) {
            if (KMAppearance.isDarkMode()) {
                color = NSColor(red: 1, green: 1, blue: 1, alpha: 0.5)
            }
        }
        self.titleLabel.textColor = color
        self.subTitleLabel.textColor = color
        self.leftLabel.textColor = color
        self.rightLabel.textColor = color
        
        self.addButton.wantsLayer = true
        self.addButton.layer?.borderColor = NSColor(red: 153.0/255.0, green: 153.0/255.0, blue: 153.0/255.0, alpha: 1).cgColor
        self.addButton.layer?.borderWidth = 1.0
        self.addButton.layer?.cornerRadius = 4.0
        self.removeButton.wantsLayer = true
        self.removeButton.layer?.borderColor = NSColor(red: 153.0/255.0, green: 153.0/255.0, blue: 153.0/255.0, alpha: 1).cgColor
        self.removeButton.layer?.borderWidth = 1.0
        self.removeButton.layer?.cornerRadius = 4.0
        
        self.addButton.isEnabled = false
        self.removeButton.isEnabled = false
        
        self.defaultItemsTableView.registerForDraggedTypes([KMPasteboardTypeAllowedIndexSet, KMPasteboardTypeDefaultIndexSet])

        self._loadAllowedItems()
        self._loadDefaultItems()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
    }
    
    @IBAction @objc func okButtonAction(_ sender: NSButton) {
        NSApp.endSheet(self.view.window!)
        self.view.window?.close()
        if self.toolbar?.toolbarIdentifier != nil && self._defaultItems.count > 0 {
            if let data = self.toolbar?.toolbarIdentifier {
                UserDefaults.standard.set(self._defaultItems, forKey: data)
            }
            NotificationCenter.default.post(name: KMToolbarCustomChangeNotification, object: self.toolbar)
        }
    }
    
    @IBAction @objc func cancelButtonAction(_ sender: NSButton) {
        NSApp.endSheet(self.view.window!)
        self.view.window?.close()
    }
    
    @IBAction @objc func resetButtonAction(_ sender: NSButton) {
        if let data = self.toolbar?.toolbarIdentifier {
            UserDefaults.standard.removeObject(forKey: data)
            NotificationCenter.default.post(name: KMToolbarCustomChangeNotification, object: self.toolbar)
        }
        
        self._loadDefaultItems()
        self.allowedItemsTableView.reloadData()
        self.defaultItemsTableView.reloadData()
    }
    
    @IBAction @objc func addButtonAction(_ sender: NSButton) {
        let selectedRowIndexes = self.allowedItemsTableView.selectedRowIndexes
        if (selectedRowIndexes.count <= 0) {
            return
        }
        var itemIdentifiers: [String] = []
        for index in selectedRowIndexes {
            itemIdentifiers.append(self._allowedItems[index])
        }
        if (itemIdentifiers.count > 0) {
            var isAdded = false
            for itemIdentifier in itemIdentifiers {
                if self._defaultItems.contains(itemIdentifier) == false || itemIdentifier == KMToolbarSpaceItemIdentifier {
                    self._defaultItems.append(itemIdentifier)
                    isAdded = true
                }
            }
            if (isAdded) {
                self.allowedItemsTableView.reloadData()
                self.defaultItemsTableView.reloadData()
                self.defaultItemsTableView.scrollRowToVisible(self._defaultItems.count-1)
                self.addButton.isEnabled = false
            } else {
                
            }
        }
    }
    
    @IBAction @objc func removeButtonAction(_ sender: NSButton) {
        let selectedRowIndexes = self.defaultItemsTableView.selectedRowIndexes
        if (selectedRowIndexes.count <= 0) {
            return
        }
        for index in selectedRowIndexes {
            if index < self._defaultItems.count {
                self._defaultItems.remove(at: index)
            }
        }
        
        self.allowedItemsTableView.reloadData()
        self.defaultItemsTableView.reloadData()
        self.removeButton.isEnabled = false
    }
    
    @objc func delete(_ sender: Any?) {
        if self.defaultItemsTableView.isEqual(to: self.view.window?.firstResponder) {
            self.removeButtonAction(self.removeButton)
        }
    }
}

extension KMToolbarCustomViewController: NSTableViewDelegate, NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
        var rows = 0
        if (self.allowedItemsTableView.isEqual(to: tableView)) {
            rows = self._allowedItems.count
        } else if (self.defaultItemsTableView.isEqual(to: tableView)) {
            rows = self._defaultItems.count
        }
        return rows
    }
    
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        var cellView: NSTableCellView?
        var itemIdentifier: String?
        if (self.allowedItemsTableView == tableView) {
            cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMAllowedItemsCell"), owner: self) as! NSTableCellView
            itemIdentifier = self._allowedItems[row]
        } else if (self.defaultItemsTableView == tableView) {
            cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMDefaultItemsCell"), owner: self) as! NSTableCellView
            itemIdentifier = self._defaultItems[row]
        }
        if itemIdentifier == KMToolbarSpaceItemIdentifier || itemIdentifier == KMNewToolbarSpaceItemIdentifier {
            cellView?.textField?.stringValue = KMLocalizedString("", nil)
            cellView?.imageView?.image = NSImage(named: KMImageNameToolbarSpace)
        } else {
            if let data = self.toolbar?.delegate?.toolbar?(self.toolbar!, itemFor: itemIdentifier!) {
                if itemIdentifier == KMToolbarFormAlignmentIdentifier {
                    cellView?.textField?.stringValue = KMLocalizedString("Alignment", nil)
                } else {
                    cellView?.textField?.stringValue = data.titleName ?? ""
                }
                cellView?.imageView?.image = data.image
            }
        }
        if let data = cellView?.isKind(of: KMToolbarCellView.self), data {
            if self._defaultItems.contains(itemIdentifier!) && itemIdentifier != KMToolbarSpaceItemIdentifier {
                (cellView as? KMToolbarCellView)?.tickImageView.image = NSImage(named: "KMImageNameToolbarSelected")
            } else {
                (cellView as? KMToolbarCellView)?.tickImageView.image = nil
            }
        }
        return cellView;
    }
    
    func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
        if (self.allowedItemsTableView == tableView) {
            let itemIdentifier = self._allowedItems[row]
            if (self._defaultItems.contains(itemIdentifier) && itemIdentifier != KMToolbarSpaceItemIdentifier) {
                return false
            }
        }
        return true
    }
    
    func tableViewSelectionDidChange(_ notification: Notification) {
        self.allowedItemsTableView.delegate = nil
        self.defaultItemsTableView.delegate = nil
        let tableView = notification.object as? NSTableView
        if (self.allowedItemsTableView == tableView) {
            self.addButton.isEnabled = tableView!.selectedRowIndexes.count > 0 ? true : false
            let set = NSIndexSet()
            self.defaultItemsTableView.selectRowIndexes(set as IndexSet, byExtendingSelection: false)
            self.removeButton.isEnabled = false
        } else if (self.defaultItemsTableView == tableView) {
            self.removeButton.isEnabled = tableView!.selectedRowIndexes.count > 0 ? true : false
            let set = NSIndexSet()
            self.allowedItemsTableView.selectRowIndexes(set as IndexSet, byExtendingSelection: false)
            self.addButton.isEnabled = false
        }
        self.allowedItemsTableView.delegate = self
        self.defaultItemsTableView.delegate = self
    }
    
    func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
        let indexSetData = NSKeyedArchiver.archivedData(withRootObject: rowIndexes)
        if (self.allowedItemsTableView == tableView) {
            pboard.declareTypes([KMPasteboardTypeAllowedIndexSet], owner: self)
            pboard.setData(indexSetData, forType: KMPasteboardTypeAllowedIndexSet)
        } else if (self.defaultItemsTableView == tableView) {
            pboard.declareTypes([KMPasteboardTypeDefaultIndexSet], owner: self)
            pboard.setData(indexSetData, forType: KMPasteboardTypeDefaultIndexSet)
        }
        return true
    }
    
    func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
        if (self.defaultItemsTableView == tableView) {
            if (dropOperation == .on) {
                return NSDragOperation(rawValue: 0)
            }
            return .move
        }
        return NSDragOperation(rawValue: 0)
    }
    
    func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
        if (self.defaultItemsTableView == tableView) {
            let pboard = info.draggingPasteboard
            if pboard.availableType(from: [KMPasteboardTypeAllowedIndexSet]) != nil {
                let rowData = pboard.data(forType: KMPasteboardTypeAllowedIndexSet)
                let rowIndexes: IndexSet = NSKeyedUnarchiver.unarchiveObject(with: rowData!) as! IndexSet
                var isAdded = false
                for idx in rowIndexes.reversed() {
                    let itemIdentifier = self._allowedItems[idx]
                    if self._defaultItems.contains(itemIdentifier) == false || itemIdentifier == KMToolbarSpaceItemIdentifier {
                        self._defaultItems.insert(itemIdentifier, at: row)
                        isAdded = true
                    }
                }

                if (isAdded) {
                    self.allowedItemsTableView.reloadData()
                    self.defaultItemsTableView.reloadData()
                    return true
                } else {
                    
                }
            } else if pboard.availableType(from: [KMPasteboardTypeDefaultIndexSet]) != nil {
                let rowData = pboard.data(forType: KMPasteboardTypeDefaultIndexSet)
                let indexes: IndexSet = NSKeyedUnarchiver.unarchiveObject(with: rowData!) as! IndexSet
                var items: [String] = []
                for item in self._defaultItems {
                    items.append(item)
                }
                
                var moveItems: [String] = []
                for index in indexes {
                    moveItems.append(self._defaultItems[index])
                }
                
                var index = 0
                for index in indexes {
                    self._defaultItems.remove(at: index)
                }
                var _row = row
                if (_row > 0) {
                    var item: String? = items[row-1]
                    while (moveItems.contains(item ?? "")) {
                        _row -= 1
                        if (_row < 0) {
                            item = nil
                            break
                        } else {
                            item = items[_row]
                        }
                    }
                    if (item != nil) {
                        index = self._defaultItems.firstIndex(of: item!)!+1
                    }
                }
                for i in 0 ..< moveItems.count {
                    self._defaultItems.insert(moveItems[i], at: index+i)
                }
                self.allowedItemsTableView.reloadData()
                self.defaultItemsTableView.reloadData()
                return true
            }
        }
        return false
    }
}

extension KMToolbarCustomViewController: NSMenuItemValidation {
    func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
        if (menuItem.action == #selector(delete)) {
            if (self.defaultItemsTableView != self.view.window!.firstResponder) {
                return false
            }
        }
        return true
    }
}

// MARK: - Private Methods

extension KMToolbarCustomViewController {
    private func _loadAllowedItems() {
        if let data = self.toolbar?.delegate?.toolbarAllowedItemIdentifiers?(self.toolbar!) {
            self._allowedItems = data
        }
        
        let itemArray = [KMToolbarImageToPDFItemIdentifier, KMToolbarRotateRightItemIdentifier, KMToolbarRotateLeftItemIdentifier, KMToolbarPageBreaksItemIdentifier, KMToolbarViewModeItemIdentifier, KMToolbarDisplayModeItemIdentifier, KMToolbarDividerItemIdentifier, KMToolbarShowToolbarItemIdentifier]
        for itemStr in itemArray {
            if (self._allowedItems.contains(itemStr)) {
                self._allowedItems.removeObject(itemStr)
            }
        }
    }

    private func _loadDefaultItems() {
        var itemIdentifiers: [String]? = self.toolbar?.toolbarIdentifier != nil ? (UserDefaults.standard.object(forKey: self.toolbar!.toolbarIdentifier!) as? [String]) : []
        if itemIdentifiers == nil || itemIdentifiers!.count <= 0 {
            if let items = self.toolbar?.delegate?.toolbarDefaultItemIdentifiers?(self.toolbar!) {
                itemIdentifiers = items
            }
        }
        
        self._defaultItems.removeAll()
        if (itemIdentifiers != nil) {
            for itemI in itemIdentifiers! {
                if itemI != KMToolbarDividerItemIdentifier {
                    self._defaultItems.append(itemI)
                }
            }
        } else {
            self._defaultItems = []
        }
    }
}