//
//  KMDocumentController.swift
//  PDF Reader Pro
//
//  Created by wanjun on 2022/12/5.
//

import Cocoa

let KMPDFDocumentType: String = "com.adobe.pdf"
let KMPDFBundleDocumentType: String = "net.sourceforge.skim-app.pdfd"
let KMNotesDocumentType: String = "net.sourceforge.skim-app.skimnotes"
let KMNotesTextDocumentType: String = "public.plain-text"
let KMNotesRTFDocumentType: String = "public.rtf"
let KMNotesRTFDDocumentType: String = "com.apple.rtfd"
let KMNotesFDFDocumentType: String = "com.adobe.fdf"
let KMPostScriptDocumentType: String = "com.adobe.postscript"
let KMEncapsulatedPostScriptDocumentType: String = "com.adobe.encapsulated-postscript"
let KMDVIDocumentType: String = "org.tug.tex.dvi"
let KMXDVDocumentType: String = "org.tug.tex.xdv"
let KMFolderDocumentType: String = "public.folder"
let KMDocumentSetupAliasKey: String = "_BDAlias"
let KMDocumentSetupFileNameKey: String = "fileName"

class KMDocumentController: NSDocumentController {
    
    func fetchUniquePath(_ originalPath: String) -> String {
        var path = originalPath
        let dManager = FileManager.default
        if !dManager.fileExists(atPath: path) {
            if path.extension.count < 1 {
                path = path.stringByAppendingPathExtension("pdf")
            }
            return path
        } else {
            let originalFullFileName = path.lastPathComponent
            let originalFileName = path.lastPathComponent.deletingPathExtension.lastPathComponent
            let originalExtension = path.extension

            let startIndex: Int = 0
            let endIndex: Int = startIndex + originalPath.count - originalFullFileName.count - 1
            let fileLocatePath = originalPath.substring(to: endIndex)
            var i = 1
            while (1 != 0) {
                var newName = String(format: "%@%ld", originalFileName, i)
                newName = String(format: "%@%@", newName, originalExtension)
                let newPath = fileLocatePath.stringByAppendingPathComponent(newName)
                if !dManager.fileExists(atPath: newPath) {
                    return newPath
                } else {
                    i+=1
                    continue
                }
            }
        }
    }
    
    func kNewDocumentTempSavePath(_ fileName: String) -> String {
        let searchPath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last
        let append1 = searchPath?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!)
        let append2 = append1!.stringByAppendingPathComponent(String(format: "%@", fileName))
        return append2
    }
    
    func savePdf(_ filePath: String) -> Void {
        let pdfData = try! Data(contentsOf: URL(fileURLWithPath: filePath))
        let document = try! self.makeUntitledDocument(ofType: KMPDFDocumentType) as NSDocument
        if ((try? document.read(from: pdfData, ofType: KMPDFDocumentType)) != nil) {
            self.addDocument(document)
            document.makeWindowControllers()
            document.showWindows()
        }
            
    }
    
    // MARK: Action
    
    @IBAction func importFromFile(_ sender: Any) {
        
    }
    
    @IBAction func openBlankPage(_ sender: Any) {
        let fileName = String(format: "%@.pdf", NSLocalizedString("Untitled", comment: ""))
        let savePath = fetchUniquePath(kNewDocumentTempSavePath(fileName))
        let pdfDocument = CPDFDocument()
        pdfDocument?.insertPage(CGSize(width: 595, height: 842), at: 0)
        pdfDocument?.write(to: URL(fileURLWithPath: savePath))
        NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: savePath), display: true) { document, documentWasAlreadyOpen, error in
            if error != nil {
                NSApp.presentError(error!)
                return
            }
            if document is KMMainDocument {
                let newDocument = document
                (newDocument as! KMMainDocument).isNewCreated = false
            }
        }
    }

    @IBAction func newDocumentFromImage(_ sender: Any) {
//        let openPanel = NSOpenPanel()
//        openPanel.allowedFileTypes = KMImageAccessoryController.supportedImageTypes()
//        openPanel.allowsMultipleSelection = true
//        openPanel.message = NSLocalizedString("Select images to create a new document. To select multiple files press cmd ⌘ button on keyboard and click on the target files one by one.", comment: "")
//        openPanel.beginSheetModal(for: NSApp.mainWindow!) { response in
//            let savePath = self.kNewDocumentTempSavePath("convertToPDF.pdf")
//            if response == .OK {
//                KMConvertPDFManager.convertImages(openPanel.urls, savePath: savePath) { success, errorDic in
//                    if !success || !FileManager.default.fileExists(atPath: savePath) {
//                        if FileManager.default.fileExists(atPath: savePath) {
//                            try? FileManager.default.removeItem(atPath: savePath)
//                        }
//
//                        let alert = NSAlert()
//                        alert.alertStyle = .critical
//                        alert.messageText = NSLocalizedString("Conversion Failed", comment: "")
//                        alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
//                        alert.runModal()
//                        return
//                    }
//                    self.savePdf(savePath)
//                    try? FileManager.default.removeItem(atPath: savePath)
//                }
//            }
//        }
    }
    
    @IBAction func importFromWebPage(_ sender: Any) {
        let windowController: KMURLToPDFWindowController = KMURLToPDFWindowController.init(windowNibName: NSNib.Name("KMURLToPDFWindowController"))
        
        windowController.beginSheetModalForWindow(NSWindow.currentWindow()) { filePath in
            if FileManager.default.fileExists(atPath: filePath) {
                NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: filePath), display: true) { document, documentWasAlreadyOpen, error in
                    if error != nil {
                        NSApp.presentError(error!)
                        return
                    }
                    if document is KMMainDocument {
                        (document as! KMMainDocument).isNewCreated = true
                    }
                }
            }
        }
    }

    
    @IBAction func importFromScanner(_ sender: Any) {
        
    }
}

extension NSDocumentController {
    func openDocumentWithURLFromPasteboard(_ pboard: NSPasteboard, showNotes: Bool, outError: NSErrorPointer) -> Any? {
        guard let theURLs = NSURL.readURLs(from: pboard), let theURL = theURLs.first else {
            if showNotes == false {
                outError?.pointee = NSError.readPasteboardError(withLocalizedDescription: NSLocalizedString("Unable to load data from clipboard", comment: "Error description"))
            }
            return nil
        }
        
//        guard (theURL as AnyObject).isFileURL else {
//            if showNotes == false {
//                return SKDownloadController.shared.addDownload(for: theURL)
//            }
//            return nil
//        }
        
        var document: Any?
        do {
            let type = try self.typeForContents(of: theURL as! URL)
//            if showNotes == false || KMNotesDocument.readableTypes.contains(type) {
//                document = try self.openDocument(withContentsOf: theURL as! URL, display: true)
//            } else 
            if KMMainDocument.readableTypes.contains(type) {
                for doc in self.documents {
                    if let sourceURL = (doc as? NSObject)?.value(forKey: "sourceFileURL") as? URL, sourceURL == theURL as! URL {
                        document = doc
                        break
                    }
                }
                if let existingDoc = document as? NSDocument {
                    existingDoc.showWindows()
                } else {
                    var error: NSError?
                    var data: Data?
                    
                    if NSWorkspace.shared.type(type, conformsToType: KMPDFBundleDocumentType) {
                        let skimFileURL = try self.bundledFileURLWithExtension("skim", inPDFBundleAtURL: theURL as! URL)
                        data = try Data(contentsOf: skimFileURL)
                        
                    } 
//                    else {
//                        data = try SKNExtendedAttributeManager.shared().extendedAttributeNamed(SKIM_NOTES_KEY, atPath: theURL.path, traverseLink: true)
//                    }
                    
//                    let newDocument = try makeUntitledDocument(ofType: KMNotesDocumentType)
//                    newDocument.sourceFileURL = theURL
//
//                    if data == nil || newDocument.read(from: data ?? Data(), ofType: KMNotesDocumentType) {
//                        self.addDocument(newDocument)
//                        newDocument.makeWindowControllers()
//                        newDocument.showWindows()
//                    } else {
//                        document = nil
//                        outError?.pointee = error
//                    }
                }
            }
        } catch {
            outError?.pointee = error as NSError
        }
        
        return document
    }
    
    func bundledFileURLWithExtension(_ extension: String, inPDFBundleAtURL theURL: URL) throws -> URL {
        let bundleContents = try FileManager.default.contentsOfDirectory(at: theURL, includingPropertiesForKeys: nil, options: [])
        for fileURL in bundleContents {
            if fileURL.pathExtension == `extension` {
                return fileURL
            }
        }
        throw NSError(domain: "YourDomain", code: 404, userInfo: [NSLocalizedDescriptionKey: "File with extension not found in PDF bundle"])
    }

    
    func openDocumentWithImageFromPasteboard(_ pboard: NSPasteboard, error outError: NSErrorPointer) -> Any? {
        var document: NSDocument?
        var data: Data?
        var type: String?
        
        if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.pdf.rawValue]) {
            pboard.types
            data = pboard.data(forType: NSPasteboard.PasteboardType.pdf)
            type = KMPDFDocumentType
        } else if pboard.canReadItem(withDataConformingToTypes: [KMEncapsulatedPostScriptDocumentType]) {
            pboard.types
            data = pboard.data(forType: NSPasteboard.PasteboardType(rawValue: KMEncapsulatedPostScriptDocumentType))
            type = isEncapsulatedPostScriptData(data!) ? KMEncapsulatedPostScriptDocumentType : KMPostScriptDocumentType
        } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.tiff.rawValue]) {
            pboard.types
            data = convertTIFFDataToPDF(pboard.data(forType: NSPasteboard.PasteboardType.tiff)!)
            type = KMPDFDocumentType
        } else {
            let images = pboard.readObjects(forClasses: [NSImage.self], options: [:]) as? [NSImage]
            let strings = pboard.readObjects(forClasses: [NSAttributedString.self], options: [:]) as? [NSAttributedString]
            if let images = images, images.count > 0 {
                data = convertTIFFDataToPDF(images[0].tiffRepresentation!)
                type = KMPDFDocumentType
            } else if let strings = strings, strings.count > 0 {
                data = KMOCTool.convertStringsToPDF(withString: strings) // convertStringsToPDF(strings!)
                type = KMPDFDocumentType
            }
        }
        
        if let data = data, let type = type {
            var error: NSError?
            
            document = try?makeUntitledDocument(ofType: type)
            
            if ((try?document?.read(from: data, ofType:type)) != nil) {
                addDocument(document!)
                document?.makeWindowControllers()
                document?.showWindows()
            } else {
                document = nil
                if let outError = outError {
                    outError.pointee = error
                }
            }
        } else if let outError = outError {
            outError.pointee = NSError.readPasteboardError(withLocalizedDescription: NSLocalizedString("Unable to load data from clipboard", comment: "Error description"))
        }
        
        return document
    }
    
    func isEncapsulatedPostScriptData(_ data: Data) -> Bool {
        let epsHeaderData = Data(bytes: [69, 80, 83, 70, 45], count: 5)
        let rg: Range = (14..<20)
        return (data.count >= 20 && (data.range(of: epsHeaderData, options: .anchored, in: rg) != nil))
    }
    
    func convertTIFFDataToPDF(_ tiffData: Data) -> Data? {
        guard let imsrc = CGImageSourceCreateWithData(tiffData as CFData, [kCGImageSourceTypeIdentifierHint: kUTTypeTIFF] as CFDictionary), CGImageSourceGetCount(imsrc) > 0, let cgImage = CGImageSourceCreateImageAtIndex(imsrc, 0, nil) else { return nil }
        let pdfData = NSMutableData(capacity: tiffData.count)
        let consumer = CGDataConsumer(data: pdfData! as CFMutableData)!
        
        var rect = CGRect(x: 0, y: 0, width: CGFloat(cgImage.width), height: CGFloat(cgImage.height))
        let ctxt = CGContext(consumer: consumer, mediaBox: &rect, nil)
        ctxt!.beginPDFPage(nil)
        ctxt!.draw(cgImage, in: rect)
        ctxt!.endPDFPage()
        ctxt!.closePDF()
        
        return pdfData as? Data
    }

}