//
//  KMPDFDigitalSignViewController.swift
//  PDF Reader Pro Edition
//
//  Created by Niehaoyu on 2023/10/19.
//

import Cocoa

class KMPDFDigitalSignViewController: NSViewController, CPDFViewDelegate {

    @IBOutlet weak var contendView: NSView!
    @IBOutlet weak var headerView: NSView!
    @IBOutlet weak var tipLabel: NSTextField!
    @IBOutlet weak var exitBox: NSBox!
    @IBOutlet weak var exitButton: KMCustomButton!
    @IBOutlet weak var saveBox: NSBox!
    @IBOutlet weak var saveButton: KMCustomButton!
    
    @IBOutlet weak var stateBGView: NSView!
    @IBOutlet weak var stateLbl: NSTextField!
    @IBOutlet weak var stateButton: NSButton!
    
    @IBOutlet weak var pdfContendView: NSView!
    @IBOutlet weak var contentTopConst: NSLayoutConstraint!
    
    
    var editWidgeAnnotation: CPDFSignatureWidgetAnnotation!
    var stateVC: CDSignatureCertificateStateViewController!
    
    @objc var scaleFactor: CGFloat = 0
    @objc var url: URL!
    @objc var password = String()
    @objc var currentPageIndex: Int = 0
    
    var signatures = NSArray()
    var type:CPromptSignaturesState = .failure
    
    @objc var titleChangeBlock: ((_ title: String, _ pageIndex: NSInteger)->Void)?
    @objc var buttonActionBlock: ((_ actionType: DSignatureActionType, _ isChanged: Bool)->Void)?
    
    var pdfView: CPDFDigtalView!
    
    override func viewDidAppear() {
        super.viewDidAppear()
        
        let contextString = NSLocalizedString("Please box an area for the signature to be added, then you can add a new digital signature.", comment: "")
        _ = CustomAlertView.alertView(message: contextString, fromView: self.view, withStyle: .black)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
        
        self.contendView.wantsLayer = true
        self.contendView.layer?.backgroundColor = KMAppearance.Layout.bgColor().cgColor
        
        self.headerView.wantsLayer = true
        self.headerView.layer?.backgroundColor = KMAppearance.Interactive.a0Color().cgColor
        
        self.tipLabel.stringValue = NSLocalizedString("You are Under Digital Sign Mode", comment: "")
        
        self.exitBox.borderColor = KMAppearance.Layout.w70Color()
        self.exitBox.borderWidth = 1.0
        self.exitButton.title = NSLocalizedString("Exit", comment: "")
        
        self.saveBox.fillColor = NSColor.white
        self.saveButton.title = NSLocalizedString("Exit", comment: "")
        self.saveButton.setTitleColor(KMAppearance.Interactive.a0Color())
        
        self.exitBox.isHidden = true
        
        self.pdfView = CPDFDigtalView.init(frame: self.pdfContendView.bounds)
        self.pdfView.autoresizingMask = [.width, .height]
        
        let document = CPDFDocument.init(url: self.url)
        if self.password.count > 0 {
            document?.unlock(withPassword: self.password)
        }
        self.pdfView.delegate = self
        self.pdfView.document = document
        self.pdfView.autoScales = true
        self.pdfView.pdfListViewDelegate = self
        self.pdfContendView.addSubview(self.pdfView)
        
        self.stateBGView.wantsLayer = true
        self.stateBGView.layer?.backgroundColor = KMAppearance.Else.textHighlightColor().cgColor
        self.stateLbl.textColor = NSColor.labelColor
        
        self.reloadState()
        
        NotificationCenter.default.addObserver(self, selector: #selector(signatureStateChangeNoti), name: NSNotification.Name(rawValue: "CSignatureTrustCerDidChangeNotification"), object: nil)

    }
    
    //MARK: Public Method
    
    func reloadState() {
        if self.pdfView.signatures.count > 0 {
            self.stateBGView.isHidden = false
            self.contentTopConst.constant = 44
        } else {
            self.stateBGView.isHidden = true
            self.contentTopConst.constant = 0
        }
        
        self.signatures = self.pdfView.signatures! as NSArray
        
        var isSignVerified = false
        var isCertTrusted = false
        
        for item in self.signatures {
            let signature: CPDFSignature = item as! CPDFSignature
            if signature.signers != nil {
                let signer = signature.signers.first
                if signer?.isCertTrusted == false {
                    isCertTrusted = false
                    break
                } else {
                    isCertTrusted = true
                }
            }
        }
        
        for item in self.signatures {
            let signature: CPDFSignature = item as! CPDFSignature
            if signature.signers != nil {
                let signer = signature.signers.first
                if signer?.isSignVerified == false {
                    isSignVerified = false
                    break
                } else {
                    isSignVerified = true
                }
            }
        }
        
        self.stateBGView.isHidden = false
        
        if (isSignVerified && isCertTrusted) {
            self.type = .Success;
        } else if(isSignVerified && !isCertTrusted) {
            self.type = .Unknown;
        } else {
            self.type = .failure;
        }
        
        if (.Success == self.type) {
            self.stateButton.image = NSImage(named: "ImageNameSigntureVerifySuccess")
            self.stateLbl.stringValue = NSLocalizedString("Signature is valid.", comment: "")
        } else if(.Unknown == self.type) {
            self.stateButton.image = NSImage(named: "ImageNameSigntureTrustedFailure")
            if(self.signatures.count > 1) {
                self.stateLbl.stringValue = NSLocalizedString("At least one signature is invalid.", comment: "")
            } else {
                self.stateLbl.stringValue = NSLocalizedString("Signature is invalid", comment: "")
            }
        } else {
            self.stateButton.image = NSImage(named: "ImageNameSigntureVerifyFailure")
            if(self.signatures.count > 1) {
                self.stateLbl.stringValue = NSLocalizedString("At least one signature is invalid.", comment: "")
            } else {
                self.stateLbl.stringValue = NSLocalizedString("Signature is invalid", comment: "")
            }
        }
    }
    
    func writeSignatureToWidget(_ widget: CPDFSignatureWidgetAnnotation, _ path: String, _ password: String, _ config: CPDFSignatureConfig, _ isLock: Bool) ->() {
        
        let fileName = self.pdfView.document.documentURL?.lastPathComponent
        let fileNameWithoutExtension = URL(fileURLWithPath: fileName!).deletingPathExtension().lastPathComponent

        let outputSavePanel = NSSavePanel()
        outputSavePanel.directoryURL = self.pdfView.document.documentURL.deletingLastPathComponent()
        outputSavePanel.title = NSLocalizedString("", comment: "Save as PDF")
        outputSavePanel.allowedFileTypes = ["pdf"]
        outputSavePanel.nameFieldStringValue = fileNameWithoutExtension + "_" + NSLocalizedString("Signed", comment: "")
        let result = outputSavePanel.runModal()
        if result == .OK {
            let contentArr = NSMutableArray()
            var locationStr = ""
            var reasonStr = NSLocalizedString("none", comment: "")
            for item in config.contents {
                if item.key == NSLocalizedString("Reason", comment: "") {
                    if item.value == NSLocalizedString("<your signing reason here>", comment: "") {
                        item.value = " " + NSLocalizedString("none", comment: "")
                    }
                    reasonStr = item.value
                } else if item.key == NSLocalizedString("Location", comment: "") {
                    if item.value == NSLocalizedString("<your signing location here>", comment: "") {
                        item.value = " "
                    }
                    locationStr = item.value
                }
                contentArr.add(item)
            }
            config.contents = contentArr as? [CPDFSignatureConfigItem]
            widget.signAppearanceConfig(config)
            
            let success = self.pdfView.document.writeSignature(to: outputSavePanel.url, withWidget: widget, pkcs12Cert: path, password: password, location: locationStr, reason: reasonStr, permissions: .forbidChange)
            widget.removeSignature()
            if success {
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
                    NSDocumentController.shared.openDocument(withContentsOf: outputSavePanel.url!, display: true) { document, documentWasAlreadyOpen, error in
                        if error != nil {
                            NSApp.presentError(error!)
                            return
                        }
                    }
                }
            } else {
                let alert = NSAlert.init()
                alert.messageText = NSLocalizedString("Save failed!", comment: "")
                alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
                alert.runModal()
            }
            widget.page.removeAnnotation(widget)
            self.pdfView.setNeedsDisplayAnnotationViewFor(widget.page)
        } else {
            widget.page.removeAnnotation(widget)
            self.pdfView.setNeedsDisplayAnnotationViewFor(widget.page)
        }
    }
 
    //MARK: Setter
    
    
    
    //MARK: IBAction
    @IBAction func exitButtonAction(_ sender: NSButton) {
        
    }
    
    @IBAction func saveButtonAction(_ sender: NSButton) {
        
//        var documentArray = NSDocumentController.shared.documents
        var didFileEdit = false
//        for i in 0...documentArray.count-1 {
//            let document = documentArray[i] 
//            if document.fileURL!.path == self.pdfView.document.documentURL.path {
//                didFileEdit = document.isDocumentEdited
//            
//                break
//            }
//        }
        guard let callBack = self.buttonActionBlock else {
            return
        }
        callBack(.cancel, didFileEdit)
        
    }
 
    
    //MARK: CPDFViewDelegate
    func pdfViewDocumentDidLoaded(_ pdfView: CPDFView!) {
        self.pdfView.go(toPageIndex: self.currentPageIndex, animated: true)
    }
    
    func setCurrentPageIndex(_ currentPageIndex: Int) {
        self.pdfView.go(toPageIndex: currentPageIndex, animated: false)
    }
    
    func pdfViewCurrentPageDidChanged(_ pdfView: CPDFView!) {
        let fileName = pdfView.document.documentURL.deletingPathExtension().lastPathComponent
        let title = String(format: "%@ (page %ld / %ld)", fileName, pdfView.currentPageIndex+1, pdfView.document.pageCount)
        
        self.currentPageIndex = pdfView.currentPageIndex
        guard let callBack = self.titleChangeBlock else {
            return
        }
        callBack(title, self.currentPageIndex)
    }

    func popUpSignatureWidgetState(_ signature: CPDFSignature, _ pdfListView: CPDFDigtalView) ->(){
        if self.stateVC == nil {
            self.stateVC = CDSignatureCertificateStateViewController.init()
        }
        self.stateVC.signature = signature
        self.stateVC.pdfListView = pdfListView
        self.stateVC.actionBlock = { [weak self, weak stateVC] stateVCSelf, actionType in
            guard let self = self, let stateVC = stateVC else { return }
            if actionType == .cancel {
                stateVC.dismiss(stateVCSelf)
            } else if actionType == .confirm {
                if let signer = signature.signers.first, let data = signer.certificates {
                    let signatureDetail = DSignatureDetailsViewController.init()
                    signatureDetail.certificates = data
                    signatureDetail.signature = signature
                    signatureDetail.pdfListView = pdfListView
                    stateVCSelf.presentAsSheet(signatureDetail)
                } else {
                    NSSound.beep()
                }
            }
        }
        if let stateVC = self.stateVC {
            self.presentAsSheet(stateVC)
            stateVC.reloadData()
        }
    }
     
    func signElectronicSignature(_ signatureWidgetAnnotation: CPDFSignatureWidgetAnnotation) -> () {
        
//        PDFCustomSignatureWindowController *signatureWindowController = [[PDFCustomSignatureWindowController alloc] init];
//        __block typeof(self) blockSelf = self;
//        [signatureWindowController beginSheetModalForWindow:[NSApp mainWindow] completionHandler:^(PDFSignature *signature){
//            if (signature) {
//                [signatureWidgetAnnotation signWithImage:signature.pathsImage];
//                [blockSelf.PDFListView setNeedsDisplayAnnotationViewForPage:signatureWidgetAnnotation.page];
//            }
//        }];
//        [signatureWindowController release];
    }
    
    //MARK: Notification
    @objc fileprivate func signatureStateChangeNoti() {
         
        let signatures = self.pdfView.document.signatures()!
        
        let tempArr = NSMutableArray()
        for signature in signatures {
            if signature.signers != nil {
                if signature.signers.count > 0 {
                    signature.verifySignature(with: self.pdfView.document)
                    tempArr.add(signature)
                }
            }
        }
        self.pdfView.signatures = tempArr as? [Any]
        
        self.reloadState()
        
        if self.stateVC != nil {
            let signatureWidget = self.editWidgeAnnotation!
            var signature = signatureWidget.signature()
            if signature == nil {
                return
            }
            self.stateVC.signature = signature
            self.stateVC.reloadData()
        }
    }
}

extension KMPDFDigitalSignViewController: CPDFDigtalViewDelegate {
    func pdfListViewAddAnnotation(_ pdfListView: CPDFDigtalView!, forAdd annotation: CPDFAnnotation!, in pdfPage: CPDFPage!) {
        
        let widget = CPDFSignatureWidgetAnnotation.init(PDFListViewNoteWith: self.pdfView.document)
        widget.bounds = CGRectMake(-1000, -1000, 545, 178);
        annotation.page.addAnnotation(widget)
        
        let configWindowVC = DSignatureConfigWindowController.init(windowNibName: "DSignatureConfigWindowController")
        configWindowVC.viewType = .fileList;
        configWindowVC.appearanceWidget = widget;
        configWindowVC.isCreatDS = false
        configWindowVC.complentionHandle = {[weak self] isSign, dic, config, isLock in
            widget.page.removeAnnotation(widget)
            if isSign {
                if (dic.object(forKey: SAVEFILEPATH_KEY) != nil) {
                    let p12Path = dic.object(forKey: SAVEFILEPATH_KEY) as! String
                    let password = dic.object(forKey: PASSWORD_KEY)
                    if p12Path.count > 0 {
                        self?.writeSignatureToWidget(annotation as! CPDFSignatureWidgetAnnotation, p12Path, password as! String, config, isLock)
                    }
                }
            }
        }
        configWindowVC.actionBlock = { controller, type in
            if (type == .cancel) {
                NSApplication.shared.stopModal()
                controller.window?.orderOut(nil)
                controller.window?.close()
            
                annotation.page.removeAnnotation(annotation)
                widget.page.removeAnnotation(widget)
                self.pdfView.setNeedsDisplayAnnotationViewFor(annotation.page)
                
            } else if (type == .confirm) {
                NSApplication.shared.stopModal()
                controller.window?.orderOut(nil)
                controller.window?.close()
            }
        }
        configWindowVC.window?.center()
        NSApplication.shared.runModal(for: configWindowVC.window!)
    }
    
    func pdfListViewEditAnnotation(_ pdfListView: CPDFDigtalView!, for anotation: CPDFAnnotation!) {
        if anotation.className == CPDFSignatureWidgetAnnotation.className() {
            let signatureWidget = anotation as! CPDFSignatureWidgetAnnotation
            var signature = signatureWidget.signature()
            if signature == nil {
                return
            }
            if signature?.signers != nil {
                self.editWidgeAnnotation = signatureWidget
                self.popUpSignatureWidgetState(signature!, self.pdfView)
            } else if signatureWidget.isSigned() {
//                self.signElectronicSignature(signatureWidget)
            } else {
                
            }
            
////            __block WindowController *weakself = self;
//            CPDFSignatureWidgetAnnotation *signatureWidget = (CPDFSignatureWidgetAnnotation *)annotation;
//            CPDFSignature *signature = [signatureWidget signature];
//            if (signature.signers.count > 0) {
//                [self popUpSignatureWidgetState:signature];
//            } else if (signatureWidget.isSigned) {
//                [self signElectronicSignature:signatureWidget];
//            } else {
//                CDSignatureSignTypeWindowController *signType = [[CDSignatureSignTypeWindowController alloc] init];
//                signType.callback = ^(CDSignType type) {
//                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//                        if(type == CDSignType_ElectronicSignature) {
//                            [weakself signElectronicSignature:signatureWidget];
//                        } else {
//                            [weakself signDigitalSignature:signatureWidget];
//                        }
//                    });
//                };
//                [signType startModal:nil];
//                [signType release];
//            }
        }
    }
    
    func pdfListViewDeleteAnnotation(_ pdfListView: CPDFDigtalView!, for anotation: CPDFAnnotation!) {
        let fileName = self.pdfView.document.documentURL?.lastPathComponent
        let fileNameWithoutExtension = URL(fileURLWithPath: fileName!).deletingPathExtension().lastPathComponent
        
        let outputSavePanel = NSSavePanel()
        outputSavePanel.directoryURL = self.pdfView.document.documentURL.deletingLastPathComponent()
        outputSavePanel.title = NSLocalizedString("", comment: "Save as PDF")
        outputSavePanel.allowedFileTypes = ["pdf"]
        outputSavePanel.nameFieldStringValue = fileNameWithoutExtension + "_" + NSLocalizedString("Signed", comment: "")
        let result = outputSavePanel.runModal()
        if result == .OK {
            let success = self.pdfView.document.write(to: outputSavePanel.url)
            if success {
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
                    NSDocumentController.shared.openDocument(withContentsOf: outputSavePanel.url!, display: true) { document, documentWasAlreadyOpen, error in
                        if error != nil {
                            NSApp.presentError(error!)
                            return
                        }
                    }
                }
            } else {
                let alert = NSAlert.init()
                alert.messageText = NSLocalizedString("Save failed!", comment: "")
                alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
                alert.runModal()
            }
        }
    }
}