//
//  KMPDFThumbnailView.swift
//  PDF Reader Pro
//
//  Created by lxy on 2022/12/15.
//

class KMPDFThumbnailView: KMThumbnailView {
    var document: CPDFDocument?
    var isShowPageSize = false
    var thumbnailSzie = NSZeroSize
    
    //标记线
    var isNeedMarkerLine: Bool = false
    var markerLineView: NSView = NSView()
    var markBeginIndexes: IndexSet = IndexSet()
    //注释状态
    var annotationShowState: KMAnnotationViewShowType = .none {
        didSet {
            self.collectionView.reloadData()
        }
    }
    //悬浮
    var hoverIndex: Int = -1
    
    var filePromiseQueue: OperationQueue = {
        let queue = OperationQueue()
        return queue
    }()
    
    fileprivate var dragFilePath: String?
    fileprivate var dragFlag = false
    fileprivate var dragIn = false
    
    var limit = false
    
    override func initDefaultValue() {
        super.initDefaultValue()
        
        self.wantsLayer = true
        self.layer?.backgroundColor = NSColor.km_init(hex: "#F7F8FA").cgColor
        
        self.thumbnailSzie = CGSize(width: 120, height: 155)
        self.minimumLineSpacing = 8
        self.collectionView.km.register(cell: KMPDFThumbnailItem.self)
        
        self.collectionView.registerForDraggedTypes(NSFilePromiseReceiver.readableDraggedTypes.map { NSPasteboard.PasteboardType($0) })
        self.collectionView.setDraggingSourceOperationMask([.copy, .delete], forLocal: false)
    }
    
    override func initSubViews() {
        super.initSubViews()
        
        self.markerLineView.wantsLayer = true
        self.markerLineView.layer?.backgroundColor = NSColor.km_init(hex: "#1770F4").cgColor
        self.markerLineView.frame = CGRectMake(0, 0, 100, 2)
        self.collectionView.addSubview(markerLineView)
        self.hiddenMarkerLineView()
        self.markerLineView.isHidden = true
    }
}

extension KMPDFThumbnailView {
    override func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
        if let size_ = self.delegate?.thumbnailView?(thumbanView: self, sizeForItemAt: indexPath) {
            return size_
        }
        
        var height: CGFloat = 0
        if let page = self.document?.page(at: UInt(indexPath.item)) {
            height = KMPDFThumbnailItem.sizeToFit(size: self.thumbnailSzie, page: page, isShow: self.isShowPageSize)
        }
        
        return NSMakeSize(collectionView.frame.size.width - 20, height)
    }
    
    override func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
        if let count = self.document?.pageCount {
            return Int(count)
        }
        return 0
    }
    
    override func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
        if let item = self.delegate?.thumbnailView?(thumbanView: self, itemForRepresentedObjectAt: indexPath) {
            return item
        }

        let cellView: KMPDFThumbnailItem = collectionView.km.dequeueReusableCell(for: indexPath)
        cellView.thumbnailView = self
        if let page_ = self.document?.page(at: UInt(indexPath.item)) {
            cellView.page = page_
        }
        cellView.annotationShowState = self.annotationShowState
        if indexPath.item == hoverIndex {
            cellView.hover = true
        } else {
            cellView.hover = false
        }
        
        cellView.mouseDownAction = { [unowned self] (view, event) in
            self.delegate?.thumbnailView?(thumbanView: self, didSelectItemAt: indexPath, object: event)
        }
        
        cellView.rightMouseDownAction = { [unowned self] (view, event) in
            self.delegate?.thumbnailView?(thumbanView: self, rightMouseDidClick: indexPath, item: view, object: event)
        }
        
        cellView.hoverCallBack = { [unowned self] view, mouseEntered in
            if let _ = self.collectionView.item(at: hoverIndex)?.view {
                let tempCell = self.collectionView.item(at: hoverIndex) as? KMPDFThumbnailItem
                tempCell?.hover = false
            }
            
            if mouseEntered {
                hoverIndex = indexPath.item
                if let _ = self.collectionView.item(at: hoverIndex)?.view {
                    let tempCell = self.collectionView.item(at: hoverIndex) as? KMPDFThumbnailItem
                    tempCell?.hover = true
                }
            } else {
                hoverIndex = -1
            }
        }
        
        return cellView
    }
    
    override func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, willBeginAt screenPoint: NSPoint, forItemsAt indexes: IndexSet) {
        if self.isNeedMarkerLine {
            self.markBeginIndexes = collectionView.selectionIndexes
        }
        
        // 将拖拽的page插入临时路径(文档)
        var indexs = IndexSet()
        for indexpath in self.dragedIndexPaths {
            indexs.insert(indexpath.item)
        }
        // 清空临时数据
        if let _path = self.dragTempFilePath, FileManager.default.fileExists(atPath: _path) {
            try?FileManager.default.removeItem(atPath: _path)
        }
            
        // 重置拖拽标识
        self.dragFlag = false
        if (indexs.count > 0) {
            let document = CPDFDocument()
            document?.importPages(indexs, from: self.document, at: 0)
            if let data = self.dragTempFloderPath, !FileManager.default.fileExists(atPath: data) {
                try?FileManager.default.createDirectory(atPath: data, withIntermediateDirectories: false)
            }
            if let data = self.dragTempFilePath, !FileManager.default.fileExists(atPath: data) {
                FileManager.default.createFile(atPath: data, contents: nil)
            }
            
            if let data = self.dragTempFilePath {
                if (self.limit) {
//                    let _ = KMTools.saveWatermarkDocument(document: document!, to: URL(fileURLWithPath: data))
                } else {
                    document?.write(to: URL(fileURLWithPath: data))
                }
            }
            self.dragFilePath = self.dragTempFilePath
        }

        return super.collectionView(collectionView, draggingSession: session, willBeginAt: screenPoint, forItemsAt: indexes)
    }
    
    override func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {
        if self.isNeedMarkerLine {
            KMPrint(collectionView)
//            if self.markBeginIndexes.count != 0 {
//                if !self.markBeginIndexes.contains(proposedDropIndexPath.pointee.item) {
                    //标记线
//                    if collectionView == self.collectionView {
                        if (self.collectionView.item(at: proposedDropIndexPath.pointee.item) != nil) {
                            var rect = self.collectionView.frameForItem(at: proposedDropIndexPath.pointee.item)
    //                        KMPrint("标记线范围 \(rect)")
                            rect.size.height = 2
                            self.markerLineView.frame = rect
                            self.markerLineView.isHidden = false
                        } else {
                            let count = self.collectionView.numberOfItems(inSection: 0)
                            if proposedDropIndexPath.pointee.item == count {
                                var rect = self.collectionView.frameForItem(at: count - 1)
        //                        KMPrint("标记线范围 \(rect)")
                                rect.origin.y += rect.size.height
                                rect.size.height = 2
                                self.markerLineView.frame = rect
                                self.markerLineView.isHidden = false
                            }
                        }
////                    }
////                }
                        print(proposedDropIndexPath.pointee.item)
//            }
        }
//        debugPrint("移动中")
        if !KMThumbnailManager.manager.dragCollectionViews.contains(collectionView) {
            KMThumbnailManager.manager.dragCollectionViews.append(collectionView)
        }

        return super.collectionView(collectionView, validateDrop: draggingInfo, proposedIndexPath: proposedDropIndexPath, dropOperation: proposedDropOperation)
    }
    
    override func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool {
        self.hiddenMarkerLineView()
        self.markBeginIndexes = IndexSet()
        self.dragIn = true
        
        let pboard = draggingInfo.draggingPasteboard
        if (pboard.availableType(from: [self.localForDraggedTypes]) != nil) {
            guard let dragIndexPath = self.dragedIndexPaths.first else {
                return false
            }
            guard let document = self.document else {
                return false
            }
            let dragIndex = dragIndexPath.item
            let toIndex = max(0, indexPath.item)
            if dragIndex < 0 || dragIndex > document.pageCount {
                return false
            }
            if (toIndex >= document.pageCount) {
                return false
            }

            if dragIndex == toIndex {
                return false
            }

            return super.collectionView(collectionView, acceptDrop: draggingInfo, indexPath: indexPath, dropOperation: dropOperation)
        } else if (pboard.availableType(from: [.localDraggedTypes]) != nil) {
            if let data = draggingInfo.draggingSource as? NSCollectionView, data.isEqual(to: collectionView) {
//                Swift.debugPrint("当前文件拖拽")
                return super.collectionView(collectionView, acceptDrop: draggingInfo, indexPath: indexPath, dropOperation: dropOperation)
            } else {
//                Swift.debugPrint("不同文件拖拽")
                if let _urlString = self.dragTempFilePath {
                    self.delegate?.thumbnailView?(thumbanView: self, didDragAddFiles: [URL(fileURLWithPath: _urlString)], indexpath: indexPath)
                }
            }
        } else if ((pboard.availableType(from: [.fileURL])) != nil) {
            if let should = self.delegate?.thumbnailView?(thumbanView: self, shouldAcceptDrop: draggingInfo, indexPath: indexPath, dropOperation: dropOperation), !should {
                return should
            }
            
            guard let pbItems = pboard.pasteboardItems else {
                return false
            }
            
            //获取url
            var array: [URL] = []
            for item in pbItems {
                guard let data = item.string(forType: .fileURL), let _url = URL(string: data) else {
                    continue
                }
                let type = _url.pathExtension.lowercased()
                if let _allowedFileTypes = self.kmAllowedFileTypes {
                    if (_allowedFileTypes.contains(type)) {
                        array.append(_url)
                    }
                } else {
                    array.append(_url)
                }
            }
            
            self.delegate?.thumbnailView?(thumbanView: self, didDragAddFiles: array, indexpath: indexPath)
        }
        
        return false
    }
    
    func collectionView(_ collectionView: NSCollectionView,
                        pasteboardWriterForItemAt indexPath: IndexPath) -> NSPasteboardWriting? {
        if let can = self.delegate?.thumbnailView?(thumbanView: self, canPasteboardWriterForItemAt: indexPath), !can {
            return nil
        }
        
        if let provider = self.delegate?.thumbnailView?(thumbanView: self, pasteboardWriterForItemAt: indexPath) {
            return provider
        }
        
        var provider: NSFilePromiseProvider?

        // 创建数据提供者
        let fileExtension = "pdf"
        if #available(macOS 11.0, *) {
            if let typeIdentifier = UTType(filenameExtension: fileExtension) {
                provider = KMFilePromiseProvider(fileType: typeIdentifier.identifier, delegate: self)
            }
        } else {
            if let typeIdentifier =
                UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension as CFString, nil) {
                provider = KMFilePromiseProvider(fileType: typeIdentifier.takeRetainedValue() as String, delegate: self)
            }
        }
        
        // 记录拖拽索引
        self.dragedIndexPaths.append(indexPath)
        do {
            if let _url = self.document?.documentURL {
                let data = try NSKeyedArchiver.archivedData(withRootObject: indexPath, requiringSecureCoding: false)
                provider?.userInfo = [KMFilePromiseProvider.UserInfoKeys.urlKey: _url,
                                      KMFilePromiseProvider.UserInfoKeys.indexPathKey: data]
            } else {
                let data = try NSKeyedArchiver.archivedData(withRootObject: indexPath, requiringSecureCoding: false)
                provider?.userInfo = [KMFilePromiseProvider.UserInfoKeys.indexPathKey: data]
            }
        } catch {
            fatalError("failed to archive indexPath to pasteboard")
        }
        return provider
    }
    
    override func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, endedAt screenPoint: NSPoint, dragOperation operation: NSDragOperation) {
//        if let _ = session.draggingPasteboard.availableType(from: [.localDraggedTypes]) {
//            Swift.debugPrint("本地拖拽")
//        } else {
        if (!self.dragIn) {
            var indexpaths = Set<IndexPath>()
            for indexpath in self.dragedIndexPaths {
                indexpaths.insert(indexpath)
            }
            // 清空数据
            self.dragedIndexPaths.removeAll()
            // 刷新数据
            self.reloadData()
            // 重新选中数据
            self.selectionIndexPaths = indexpaths
        } else {
            Swift.debugPrint("拖入文件 或 本地拖拽")
        }
        self.dragIn = false
        
        self.hiddenMarkerLineView()
        self.markBeginIndexes = IndexSet()
//        }
        
        super.collectionView(collectionView, draggingSession: session, endedAt: screenPoint, dragOperation: operation)
    }
}

extension KMPDFThumbnailView {
    func hiddenMarkerLineView() {
        for item in KMThumbnailManager.manager.dragCollectionViews {
            let view = item.superview?.superview?.superview as? KMPDFThumbnailView
            view?.markerLineView.isHidden = true
        }
        KMThumbnailManager.manager.dragCollectionViews.removeAll()
    }
}

// MARK: - KMExtensions

extension KMPDFThumbnailView {
    var dragTempFloderPath: String? {
        get {
            return NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier ?? "").stringByAppendingPathComponent("KMPDFThumbnailView_Drag_Temp")
        }
    }
    var dragTempFilePath: String? {
        get {
            return self.dragTempFloderPath?.stringByAppendingPathComponent("drag_tmp.pdf")
        }
    }
}

// MARK: - NSFilePromiseProviderDelegate

extension KMPDFThumbnailView: NSFilePromiseProviderDelegate {
    func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, fileNameForType fileType: String) -> String {
        var fileName: String = "Untitle"
        if let _string = self.document?.documentURL.deletingPathExtension().lastPathComponent {
            fileName = _string
        }
        fileName.append(" pages")
        var indexs = IndexSet()
        for indexpath in self.dragedIndexPaths {
            indexs.insert(indexpath.item)
        }
        fileName.append(" ")
        fileName.append(KMPageRangeTools.newParseSelectedIndexs(selectedIndex: indexs.sorted()))
        fileName.append(".pdf")
        
        return fileName
    }
    
    func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider,
                             writePromiseTo url: URL,
                             completionHandler: @escaping (Error?) -> Void) {
        do {
            /** Copy the file to the location provided to you. You always do a copy, not a move.
             It's important you call the completion handler.
             */
            if let _urlString = self.dragFilePath, !self.dragFlag {
                self.dragFlag = true
                if let should = self.delegate?.thumbnailView?(thumbanView: self, shouldPasteboardWriterForItemAt: IndexPath(item: 0, section: 0)), !should {
                    completionHandler(nil)
                    return 
                }
                
                try FileManager.default.copyItem(at: URL(fileURLWithPath: _urlString), to: url)
            }
            
            completionHandler(nil)
        } catch let error {
            OperationQueue.main.addOperation {
                if let win = self.window {
                    self.presentError(error, modalFor: win,
                                      delegate: nil, didPresent: nil, contextInfo: nil)
                }
            }
            completionHandler(error)
        }
    }
    
    /** You should provide a non main operation queue (e.g. one you create) via this function.
        This way you don't stall the main thread while writing the promise file.
    */
    func operationQueue(for filePromiseProvider: NSFilePromiseProvider) -> OperationQueue {
        return self.filePromiseQueue
    }
    
    // Utility function to return a PhotoItem object from the NSFilePromiseProvider.
//    func photoFromFilePromiserProvider(filePromiseProvider: NSFilePromiseProvider) -> CPDFPage? {
//        var result: CPDFPage?
//        if let userInfo = filePromiseProvider.userInfo as? [String: AnyObject] {
//            do {
//                if let indexPathData = userInfo[KMFilePromiseProvider.UserInfoKeys.indexPathKey] as? Data {
//                    if let indexPath =
//                        try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(indexPathData) as? IndexPath {
//                        result = self.document?.page(at: UInt(indexPath.item))
//                        }
//                }
//            } catch {
//                fatalError("failed to unarchive indexPath from promise provider.")
//            }
//        }
//        return result
//    }
}