//
//  KMCompareWindowController.swift
//  Cisdem PDFMaster
//
//  Created by lizhe on 2023/11/14.
//

import Cocoa

typealias KMCompareWindowControllerContentComplete = (_ controller: KMCompareWindowController, _ pdfCompareContent: CPDFCompareContent, _ results: [CPDFCompareResults]  ,_ oldDocument: CPDFDocument, _ document: CPDFDocument) -> Void
typealias KMCompareWindowControllerCoveringComplete = (_ controller: KMCompareWindowController, _ document: CPDFDocument) -> Void

class KMCompareWindowController: KMBaseWindowController {

    @IBOutlet weak var compareView: KMCompareView!
    
    var pdfCompareContent: CPDFCompareContent?
    var maskView: KMBookletMaskView?
    var progressController: SKProgressController?
    
    var filePath: String = "" {
        didSet {
            if compareView != nil {
                compareView.filePath = filePath
            }
        }
    }
    
    var fileType: KMCompareFilesType = .content {
        didSet {
            if compareView != nil {
                compareView.fileType = fileType
            }
        }
    }
    var password: String = "" {
        didSet {
            if compareView != nil {
                self.compareView.password = password
            }
        }
    }
    
    var contentComplete: KMCompareWindowControllerContentComplete?
    var coveringComplete :KMCompareWindowControllerCoveringComplete?
    
    override func windowDidLoad() {
        super.windowDidLoad()

        // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
        compareView.password = password
        compareView.filePath = filePath
        compareView.fileType = fileType
        compareView.cancelAction = { [unowned self] view in
            cancelAction?(self)
        }
        
        compareView.doneAction = { [unowned self] view, config in
            self.compareAction(config: config)
        }
    }
    
    func compareAction(config: KMCompareFilesConfig) {
        self.showWaitting()

        guard let pdfOldDocument = config.fileOldAttribute.pdfDocument, let pdfNewDocument = config.fileNewAttribute.pdfDocument else {
            let alert = NSAlert()
            alert.alertStyle = .critical
            alert.messageText = NSLocalizedString("Please select two files to compare", comment: "")
            alert.runModal()
            self.hideWaitting()
            return
        }

        let fileManager = FileManager.default
        let fileOldPath = config.fileOldAttribute.pdfDocument?.documentURL.path
        let fileNewPath = config.fileNewAttribute.pdfDocument?.documentURL.path

        if !fileManager.fileExists(atPath: fileOldPath!) || !fileManager.fileExists(atPath: fileNewPath!){
            let alert = NSAlert()
            alert.alertStyle = .critical
            alert.messageText = NSLocalizedString("The file has been deleted, please reselect a file.", comment: "")
            alert.runModal()
            self.hideWaitting()
            return
        }

        if (config.fileNewAttribute.fetchSelectPages().count == 0) ||
            (!config.fileNewAttribute.bAllPage && config.fileNewAttribute.pagesString.count < 1) {
            let alert = NSAlert()
            alert.alertStyle = .critical
            alert.messageText = String(format: "%@ %@", (config.fileNewAttribute.pdfDocument?.documentURL.path.lastPathComponent.lastPathComponent)!, NSLocalizedString("Invalid page range. Please reselect the page range.", comment: ""))
            alert.runModal()

            config.fileNewAttribute.bAllPage = true
            config.fileNewAttribute.pagesType = .all
            
            compareView.reloadData()
            
            self.hideWaitting()
            return
        }

        if (config.fileOldAttribute.fetchSelectPages().count == 0) || (!config.fileOldAttribute.bAllPage && config.fileOldAttribute.pagesString.count < 1) {
            let alert = NSAlert()
            alert.alertStyle = .critical
            alert.messageText = String(format: "%@ %@", (config.fileOldAttribute.pdfDocument?.documentURL.path.lastPathComponent.lastPathComponent)!, NSLocalizedString("Invalid page range. Please reselect the page range.", comment: ""))
            alert.runModal()

            config.fileOldAttribute.bAllPage = true
            config.fileOldAttribute.pagesType = .all

            compareView.reloadData()
            
            self.hideWaitting()
            return
        }

        let filePath = config.fileOldAttribute.pdfDocument?.documentURL.path
        let pdfDocument = CPDFDocument(url: URL(fileURLWithPath: filePath!))

        let filePath1 = config.fileNewAttribute.pdfDocument?.documentURL.path
        let pdfDocument1 = CPDFDocument(url: URL(fileURLWithPath: filePath1!))

        DispatchQueue.global().async {
            let oldDoc = CPDFDocument(url: config.fileOldAttribute.pdfDocument?.documentURL)
            oldDoc!.unlock(withPassword: config.fileOldAttribute.password)
            let doc = CPDFDocument(url: config.fileNewAttribute.pdfDocument?.documentURL)
            doc!.unlock(withPassword: config.fileNewAttribute.password)
            
            if self.compareView.fileType == .coverting {
                let pdfCompareOverlay = CPDFCompareOverlay(oldDocument: oldDoc, oldPageRange: config.fileOldAttribute.pagesString, newDocument: doc, newPageRange: config.fileNewAttribute.pagesString)
                
                let oldStrokeColor = config.oldStrokeColor
                pdfCompareOverlay?.setOldDocumentStroke(oldStrokeColor())
                pdfCompareOverlay?.setOldDocumentStrokeOpacity(config.oldStrokeOpacity())
                
                let newStrokeColor = config.newStrokeColor
                pdfCompareOverlay?.setNewDocumentStroke(newStrokeColor())
                pdfCompareOverlay?.setNewDocumentStrokeOpacity(config.newStrokeOpacity())
                pdfCompareOverlay?.setNewDocumentFillOpacity(config.newFillOpacity())
                pdfCompareOverlay?.setOldDocumentFillOpacity(config.oldFillOpacity())
                pdfCompareOverlay?.setNoFill(config.isNOFill())
                pdfCompareOverlay?.setBlendMod(config.blendMod())

                if (pdfCompareOverlay?.compare() == true) {
                    DispatchQueue.main.async {
                        self.progressController?.doubleValue = 30.0
                    }
                    
                    guard let document = pdfCompareOverlay?.comparisonDocument() else {
                        DispatchQueue.main.async {
                            let alert = NSAlert()
                            alert.alertStyle = .critical
                            alert.messageText = NSLocalizedString("Failure", comment: "")
                            alert.runModal()
                            
                            self.hideWaitting()
                        }
                        return
                    }
                    
                    
                    DispatchQueue.main.async {
                        self.hideWaitting()
                        self.coveringComplete?(self, document)
                    }
                    debugPrint("合并成功")
                }
            } else {
                var results: [CPDFCompareResults] = []
                var pdfCompareContent: CPDFCompareContent? = nil
                
//                if let _pdfCompareContent = self._pdfCompareContent {
//                    pdfCompareContent = _pdfCompareContent
//                }
//                
//                if self._compareCancel {
//                    return
//                }
                
                pdfCompareContent = CPDFCompareContent(oldDocument: oldDoc, newDocument: doc)
                
                pdfCompareContent?.setDelete(config.deleteColor())
                pdfCompareContent?.setReplace(config.replaceColor())
                pdfCompareContent?.setInsert(config.insertColor())
                pdfCompareContent?.setDeleteOpacity(config.deleteOpacity())
                pdfCompareContent?.setReplaceOpacity(config.replaceOpacity())
                pdfCompareContent?.setInsertOpacity(config.insertOpacity())
                
                let maxIndex = max(config.fileOldAttribute.fetchSelectPages().count, config.fileNewAttribute.fetchSelectPages().count)
                
                var compareType: CPDFCompareType = .all
                if config.isCompareText() && !config.isCompareImage() {
                    compareType = .text
                } else if !config.isCompareText() && config.isCompareImage() {
                    compareType = .image
                }
                
//                if self._compareCancel {
//                    return
//                }
                DispatchQueue.main.async {
                    self.progressController?.doubleValue = 30.0
                }
                
                for i in 0..<maxIndex {
                    let oldPageIndex: Int
                    if i >= config.fileOldAttribute.fetchSelectPages().count {
                        oldPageIndex = Int(oldDoc!.pageCount) + i
                    } else {
                        oldPageIndex = Int(truncating: config.fileOldAttribute.fetchSelectPages()[i] as NSNumber) - 1
                    }
                    
                    let newPageIndex: Int
                    if i >= config.fileNewAttribute.fetchSelectPages().count {
                        newPageIndex = Int(doc!.pageCount) + i
                    } else {
                        newPageIndex = Int(truncating: config.fileNewAttribute.fetchSelectPages()[i] as NSNumber) - 1
                    }

                    if let compareResults = pdfCompareContent?.compareOldPageIndex(oldPageIndex, newPageIndex: newPageIndex, type: compareType, isDrawHighlight: true) {
                        results.append(compareResults)
                    }
                    
//                    DispatchQueue.main.async {
//                        if let compareLoadingWVC = self.compareLoadingWVC {
//                            compareLoadingWVC.progress = CGFloat(i) / CGFloat(maxIndex)
//                        }
//                    }
                }
                
                DispatchQueue.main.async {
                    self.hideWaitting()
                    self.contentComplete?(self, pdfCompareContent!, results, oldDoc!, doc!)
                    if results.count > 0 {
                        // Handle success case
                    } else {
                        let alert = NSAlert()
                        alert.alertStyle = .critical
                        alert.messageText = NSLocalizedString("There is no difference between the two documents.", comment: "")
                        alert.runModal()
                    }
                }
            }
        }

    }
}

extension KMCompareWindowController {
    func showWaitting() {
        compareView.doneButton.isEnabled = false
        if self.maskView == nil {
            self.maskView = KMBookletMaskView(frame: CGRect(x: 0, y: 0, width: self.window?.frame.size.width ?? 0, height: self.window?.frame.size.height ?? 0))
        }
        self.window?.contentView?.addSubview(self.maskView!)
        
        let progress = SKProgressController()
        progress.window?.backgroundColor = NSColor.km_init(hex: "#36383B")
        progress.window?.contentView?.wantsLayer = true
        progress.window?.contentView?.layer?.backgroundColor = NSColor.km_init(hex: "#36383B").cgColor
        progress.progressField.textColor = NSColor.white
        progress.message = NSLocalizedString("Comparing documents...", comment: "")

        progress.closeBlock = { [unowned self] in
            
        }
        
        self.progressController = progress
        self.window?.beginSheet(progress.window!)
    }
    func hideWaitting() {
        compareView.doneButton.isEnabled = true
        
        DispatchQueue.main.async {
            self.progressController?.doubleValue = 99.0
        }
        
        self.maskView?.removeFromSuperview()

        if (self.progressController != nil) {
            self.window?.endSheet((self.progressController?.window)!)
            self.progressController = nil
        }
    }
}