//
//  KMPageEditTools.swift
//  PDF Reader Pro
//
//  Created by tangchao on 2023/1/11.
//

import Cocoa

enum KMPageSizeUint: String {
case mm = "mm"
case cm = "cm"
case km_in = "in"
}

class KMPageEditTools: NSObject {
    class func insert(_ document: CPDFDocument, _ index: Int, _ pages: Array<CPDFPage>) -> Bool {
//        for i in 0 ..< pages.count {
//            document.insertPageObject(pages[i], at: UInt(index+i))
//        }
        document.insertPageObject(pages.first, at: 0)
        return true
    }
    
    class func showInsertMenu(callback: (_ index: Int) -> ()) {
        
    }
    
    class func extract(_ document: CPDFDocument, _ pageIndexs: IndexSet,_ oneDocument: Bool,_ window: NSWindow, callback: @escaping (_ result: Bool, _ urls: Array<URL>?, _ error: String) -> ()) {
        /// 提取的页面
        var extractPages: Array<CPDFPage> = []
        for i in pageIndexs {
            extractPages.append(document.page(at: UInt(i)))
        }
        
        if (oneDocument) { /// 提取为一个文档
            var fileName = document.documentURL.deletingPathExtension().lastPathComponent
            fileName.append(" pages ")
            fileName.append(KMPageRangeTools.newParseSelectedIndexs(selectedIndex: pageIndexs.sorted()))
            fileName.append(".pdf")
            NSPanel.savePanel(window, true) { panel in
                panel.nameFieldStringValue = fileName
            } completion: { response, url, isOpen in
                if (response != .OK) {
                    callback(false, nil, "cancel")
                    return
                }
                
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    let saveFilePath = url!.path
                    DispatchQueue.global().async {
                        var pdf = CPDFDocument.init()
                        let success = pdf?.extractAsOneDocument(withPages: extractPages, savePath: saveFilePath) ?? false
                        DispatchQueue.main.async {
                            if (success == false) {
                                callback(false, nil, "failure")
                                return
                            }
                                 
                            if (isOpen == false) {
                                let url = URL(fileURLWithPath: saveFilePath)
                                NSWorkspace.shared.activateFileViewerSelecting([url])
                            } else {
                                NSDocumentController.shared.km_safe_openDocument(withContentsOf: URL(fileURLWithPath: saveFilePath), display: true) { _, _, _ in
                                    
                                }
                            }
                            callback(true, [URL(fileURLWithPath: saveFilePath)], "")
                        }
                    }
                }
            }

            return
        }
        
        let panel = NSOpenPanel()
        panel.canChooseFiles = false
        panel.canChooseDirectories = true
        panel.canCreateDirectories = true
        panel.allowsMultipleSelection = false
        panel.beginSheetModal(for: window) {  response in
            if response != .OK {
                callback(false, nil, "cancel")
                return
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                let outputURL = panel.url
                DispatchQueue.global().async {
                    let folderName = String(((document.documentURL?.lastPathComponent.split(separator: ".").first) ?? "")) + "_extract"
                    
                    var filePath = URL(fileURLWithPath: outputURL?.path ?? "").appendingPathComponent(folderName).path
                    var i = 1
                    let testFilePath = filePath
                    while FileManager.default.fileExists(atPath: filePath) {
                        filePath = testFilePath + "\(i)"
                        i += 1
                    }
                    
                    try? FileManager.default.createDirectory(atPath: filePath, withIntermediateDirectories: false, attributes: nil)
                    
                    let successArray = document.extractPerPageDocument(withPages: extractPages, folerPath: filePath) ?? []
                    DispatchQueue.main.async {
                        if successArray.count == 0 {
                            callback(false, nil, "failure")
                            return
                        }
                        NSWorkspace.shared.activateFileViewerSelecting(successArray)
                            
                        callback(true, successArray, "")
                    }
                }
            }
        }
    }
    
    class func split(_ document: CPDFDocument, _ avgNumberPage: Int, _ path: String, _ filename: String, callback: @escaping (_ result: Bool, _ outputDocuments: Array<CPDFDocument>?, _ error: String) -> ()) {
        if (avgNumberPage == 0) {
            callback(false, nil, "avgNumberPage = 0.")
            return
        }
        var fileCount: Int = (Int(document.pageCount) / avgNumberPage) + 1
        var files: Array<IndexSet> = []
        for i in 0 ..< fileCount {
            var indexs: IndexSet = []
            for j in 0 ..< avgNumberPage {
                if (i * avgNumberPage + j >= document.pageCount) {
                    break
                }
                indexs.insert(i * avgNumberPage + j)
            }
            files.append(indexs)
        }
        
        var array: Array<CPDFDocument> = []
        for indexs in files {
            let document_new: CPDFDocument = CPDFDocument()
            document_new.importPages(indexs, from: document, at: 0)
            array.append(document_new)
            
//            document_new.write(to: <#T##URL!#>)
        }
        callback(true, array, "")
    }
    
    class func split(_ document: CPDFDocument, _ model: KMPageEditSplitSettingModel, _ path: String, _ filename: String, callback: @escaping (_ result: Bool, _ outputFilepaths: Array<String>?, _ error: String) -> ()) {
        let file_indexs = model.getSplitIndexSets ?? []
        if (file_indexs.count <= 0) {
            callback(false, nil, "")
            return
        }
        
        let filePath = "\(path)/\(document.documentURL.deletingPathExtension().lastPathComponent)"
        if (!FileManager.default.fileExists(atPath: filePath)) {
            try?FileManager.default.createDirectory(atPath: filePath, withIntermediateDirectories: true)
        }
        
        var filepaths: [String] = []
        for i in 0 ..< file_indexs.count {
            let indexs = file_indexs[i]
            let filepath = String(format: "%@/%@ %d.pdf", filePath, filename, i+1)
            filepaths.append(filepath)
            
            let newDocument = CPDFDocument()
            newDocument?.importPages(indexs, from: document, at: 0)
            newDocument?.write(to: URL(fileURLWithPath: filepath))
        }
        
        callback(true, filepaths, "")
    }
    
    class func reverse(_ document: CPDFDocument, _ selectedIndexs: IndexSet, callback: @escaping (_ result: Bool, _ error: String) -> ()) {
        if (document.pageCount <= 0) {
            callback(false, "")
            return
        }
        if (selectedIndexs.count <= 1) {
            callback(false, "")
            return
        }
        
        var pages: Array<CPDFPage> = []
        for i in 0 ..< document.pageCount {
            if (selectedIndexs.contains(IndexSet.Element(i))) {
                pages.append(document.page(at: i))
            }
            
        }
        
        var first: Int = 0
        var last: Int = pages.count-1
        while (last > first) {
            let beforePage: CPDFPage = pages[first]
            let afterPage: CPDFPage = pages[last]
            let beforeIndex = document.index(for: beforePage)
            let afterIndex = document.index(for: afterPage)
            
            document.removePage(at: UInt(afterIndex))
            document.removePage(at: UInt(beforeIndex))
            
            document.insertPageObject(afterPage, at: UInt(beforeIndex))
            document.insertPageObject(beforePage, at: UInt(afterIndex))
            
            first += 1
            last -= 1
        }
        
        callback(true, "")
    }
    
    
    class func getPageSize() -> Array<String> {
        return KMCropTools.getPageSize()
    }
    
    class func getPageSizeValue(_ pageSize: String) -> NSSize {
        return KMCropTools.getPageSizeValue(pageSize)
    }
    
    class func getAllPageSizeUnit() -> Array<String> {
        return [KMPageSizeUint.mm.rawValue, KMPageSizeUint.cm.rawValue,KMPageSizeUint.km_in.rawValue]
    }
    
    class func convertSize(with fromUnit: KMPageSizeUint, to toUnit: KMPageSizeUint, value: CGFloat) -> String {
        var result: CGFloat = value
        if (fromUnit == toUnit) {
            
        } else if (toUnit == .cm) {
            if (fromUnit == .mm) {
                result = value / 10.0
            } else if (fromUnit == .km_in) {
                result = value * 25.4
            }
        } else if (toUnit == .mm) {
            if (fromUnit == .cm) {
                result = value * 10
            } else if (fromUnit == .km_in) {
                result = value * 10 * 25.4
            }
        } else if (toUnit == .km_in) {
            if (fromUnit == .cm) {
                result = value / 25.4
            } else if (fromUnit == .mm) {
                result = value/10.0/25.4
            }
        }
        
        if (fmodf(Float(result), 1) == 0) { /// 如果有一位小数点
            return String(format: "%.0f", result)
        } else if (fmodf(Float(result*10), 1) == 0) { //如果有两位小数点
            return String(format: "%.1f", result)
        } else {
            return String(format: "%.2f", result)
        }
    }
    
    class func sizeUnitToBoundSize(unit: KMPageSizeUint, pageSize: NSSize) -> NSSize {
        let fromUnit = unit
        let toUnit: KMPageSizeUint = .mm
        var result: NSSize = pageSize
        if (fromUnit == .cm) {
            result = NSSize(width: pageSize.width * 10, height: pageSize.height * 10)
        } else if (fromUnit == .km_in) {
            result = NSSize(width: pageSize.width * 10 * 25.4,height: pageSize.height * 10 * 25.4)
        }
        
        let width = result.width
        let height = result.height
        return NSSize(width: width * 595 / 210, height: height * 842 / 297)
    }
    
    class func boundSizeToUnitSize(size boundSize: NSSize, to toUnit: KMPageSizeUint) -> NSSize {
        let _fromUnit = toUnit
        let _toUnit: KMPageSizeUint = .mm
        var result: NSSize = boundSize
        if (_fromUnit == .cm) {
            result = NSSize(width: boundSize.width * 10, height: boundSize.height * 10)
        } else if (_fromUnit == .km_in) {
            result = NSSize(width: boundSize.width * 10 * 25.4,height: boundSize.height * 10 * 25.4)
        }
        
        let width = result.width
        let height = result.height
        return NSSize(width: width * 210 / 595, height: height * 297 / 842)
    }
}