//
//  KMSearchFindView.swift
//  PDF Reader Pro
//
//  Created by lizhe on 2024/1/17.
//

import Cocoa

typealias KMSearchFindViewDoneAction = (_ view: KMSearchFindView) -> Void
typealias KMSearchFindViewSearchAction = (_ view: KMSearchFindView, _ searchString: String, _ forward: Bool) -> Bool
typealias KMSearchFindViewShowAllAction = (_ view: KMSearchFindView, _ searchString: String, _ forward: Bool) -> Void

class KMSearchFindView: KMBaseXibView {
    @IBOutlet var findField: NSSearchField!
    @IBOutlet var messageField: NSTextField!
    @IBOutlet var doneButton: NSButton!
    @IBOutlet var navigationButton: NSSegmentedControl!
    @IBOutlet var showAllButton: NSButton!
    
    var ownerController: AnyObject?
    var findString: String?
    
    private var lastChangeCount: Int = 0
    private var didChange: Bool = false
    private var animating: Bool = false
    
    var showAllAction: KMSearchFindViewShowAllAction?
    var doneAction: KMSearchFindViewDoneAction?
    var searchAction: KMSearchFindViewSearchAction?

    override func setup() {
        findField.delegate = self
        
        refreshSearchBarMenu()
        
        self.showAllButton.title = NSLocalizedString("Show All", comment: "")
        self.doneButton.title = NSLocalizedString("Done", comment: "")
    }

    private func refreshSearchBarMenu() {
        var words = UserDefaults.standard.object(forKey: "kmDocumentSearchWordArrays") as? [String]
        if words == nil {
            UserDefaults.standard.setValue([], forKey: "kmDocumentSearchWordArrays")
            words = []
        }
        guard let words = words else { return }
        let searchMenu = NSMenu()

        for word in words {
            var tword = word
            if word.count > 15 {
                tword = String(word.prefix(15)) + "..."
            }
            let item = searchMenu.addItem(withTitle: tword, action: #selector(searchPDFKeyWord(_:)), keyEquivalent: "")
            item.representedObject = tword
        }

        let attrited = [NSAttributedString.Key.font: NSFont(name: "Helvetica", size: 12.0)!]

        if words.count > 0 {
            let attributedString = NSAttributedString(string: NSLocalizedString("Search History", comment: ""), attributes: attrited)
            let item = NSMenuItem()
            item.attributedTitle = attributedString
            searchMenu.insertItem(item, at: 0)

            searchMenu.addItem(NSMenuItem.separator())

            let attributedString1 = NSAttributedString(string: NSLocalizedString("Clear Search History", comment: ""), attributes: attrited)
            let item1 = NSMenuItem()
            item1.attributedTitle = attributedString1
            item1.action = #selector(clearSearchWordHistory(_:))
            item1.target = self
            searchMenu.addItem(item1)

            searchMenu.insertItem(NSMenuItem.separator(), at: 0)
        }

        let attributedString2 = NSAttributedString(string: NSLocalizedString("Ignore Case", comment: ""), attributes: attrited)
        let ignoreItem = NSMenuItem()
        ignoreItem.attributedTitle = attributedString2
        ignoreItem.action = #selector(toggleCaseInsensitiveFind(_:))
        ignoreItem.target = self
        searchMenu.insertItem(ignoreItem, at: 0)

        (findField.cell! as! NSSearchFieldCell).searchMenuTemplate = searchMenu
    }

    private func windowDidBecomeKey() {
        let findPboard = NSPasteboard(name: NSPasteboard.Name.find)
        if lastChangeCount < findPboard.changeCount {
            if let strings = findPboard.readObjects(forClasses: [NSString.self], options: [:]) as? [String], let firstString = strings.first {
                setFindString(firstString)
                lastChangeCount = findPboard.changeCount
                didChange = false
            }
        }
    }

    private func windowDidResignKey() {
        updateFindPboard()
    }

    private func updateFindPboard() {
        if didChange {
            let findPboard = NSPasteboard(name: NSPasteboard.Name.find)
            findPboard.clearContents()
            findPboard.writeObjects([findString! as NSPasteboardWriting])
            lastChangeCount = findPboard.changeCount
            didChange = false
        }
    }

    func setFindString(_ newFindString: String?) {
        if findString != newFindString {
            findString = newFindString
            didChange = true
        }
    }

    func findForward(_ forward: Bool) {
        var found = true
        if let findStringLength = findString?.count, findStringLength > 0 {
            guard let searchAction = searchAction else { return }
            found = searchAction(self,findString!,forward)
            updateFindPboard()

            if var words = UserDefaults.standard.object(forKey: "kmDocumentSearchWordArrays") as? [String] {
                if let index = words.firstIndex(of: findString!) {
                    words.remove(at: index)
                }
                words.insert(findString!, at: 0)

                if words.count > 10 {
                    words.removeLast()
                }

                UserDefaults.standard.set(words, forKey: "kmDocumentSearchWordArrays")
                UserDefaults.standard.synchronize()
                refreshSearchBarMenu()
            }
        }
        messageField.isHidden = found
    }

    @IBAction func find(_ sender: Any) {
        findForward((sender as AnyObject).selectedTag() == 1)
    }

    @IBAction func buttonItemClick_ShowAll(_ sender: NSButton) {
        self.findString = findField.stringValue
        showAllAction?(self, self.findString ?? "", findField.selectedTag() == 1)
    }

    @IBAction func remove(_ sender: Any) {
        doneAction?(self)
    }

    @IBAction func toggleCaseInsensitiveFind(_ sender: Any) {
//        let caseInsensitive = UserDefaults.standard.bool(forKey: SKCaseInsensitiveFindKey)
//        UserDefaults.standard.set(!caseInsensitive, forKey: SKCaseInsensitiveFindKey)
        let caseInsensitive = UserDefaults.standard.bool(forKey: SKCaseInsensitiveFindKey)
        UserDefaults.standard.set(!caseInsensitive, forKey: SKCaseInsensitiveFindKey)
    }

    @objc func clearSearchWordHistory(_ sender: Any) {
        UserDefaults.standard.removeObject(forKey: "kmDocumentSearchWordArrays")
        UserDefaults.standard.synchronize()
        refreshSearchBarMenu()
    }

    @objc func searchPDFKeyWord(_ item: NSMenuItem) {
        let word = item.representedObject as? String ?? ""
        findField.stringValue = word
        findString = word
        findForward(true)
    }
    
    @objc func searchString(_ string: String) {
        let word = string
        findField.stringValue = word
        findString = word
        findForward(true)
    }

//    override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
//        if menuItem.action == #selector(toggleCaseInsensitiveFind(_:)) {
//            menuItem.state = UserDefaults.standard.bool(forKey: SKCaseInsensitiveFindKey) ? .on : .off
//            return true
//        }
//        return true
//    }

    func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
        if commandSelector == #selector(cancelOperation(_:)) {
            doneButton.performClick(nil)
            return true
        }
        return false
    }
}

extension KMSearchFindView: NSSearchFieldDelegate {
    func searchFieldDidEndSearching(_ sender: NSSearchField) {
        print("searchFieldDidEndSearching")
    }
    
    func controlTextDidEndEditing(_ obj: Notification) {
        let fied: NSTextField = obj.object as! NSTextField;
        if fied.isEqual(self.findField) {
            print("controlTextDidEndEditing")
            findString = self.findField.stringValue
            self.find(self.findField as Any)
        }
    }
}