//
//  KMLeftSideViewController+Thumbnail.swift
//  PDF Master
//
//  Created by tangchao on 2024/1/12.
//

import Foundation

extension KMLeftSideViewController.Key {
    static let thumbSizeScaling = "KMThumbnailSizeScalingKey"
    static let thumbDisplayPageSizeKey = "kKMThumbnailDisplayPageSizeKey"
}

// MARK: - Actions

extension KMLeftSideViewController {
    public func refreshUIOfThumbnailIfNeed(preference: Bool = false) {
        if self.type.methodType != .Thumbnail {
            return
        }
        if preference {
            self.reloadThumbnailSize()
        }
        
        Task { @MainActor in
            self.thumbnailTableView.reloadData()
        }
    }
    
    public func reloadThumbnailDataIfNeed() {
        if self.type.methodType != .Thumbnail {
            return
        }
        self.resetThumbnails()
    }
    
    public func reloadThumbnailSize() {
        let defaultSize = roundf(KMPreference.shared.thumbPageSize)
        var thumbnailSize = Self.kTinySize
        if defaultSize < Self.kTinySize + Self.kFudgeSize {
            
        } else {
            if defaultSize < Self.kSmallSize + Self.kFudgeSize {
                thumbnailSize = Self.kSmallSize
            } else {
                if defaultSize < Self.kLargeSize + Self.kFudgeSize {
                    thumbnailSize = Self.kLargeSize
                } else {
                    thumbnailSize = Self.kHugeSize
                }
            }
        }
        
        if (abs(thumbnailSize - Float(self.thumbnailCacheSize)) > Self.kFudgeSize) {
            self.thumbnailCacheSize = thumbnailSize.cgFloat
        }
        
        Task { @MainActor in
            self.thumbnailTableView.reloadData()
        }
    }
    
    // 显示缩略图模块
    func showThumbnail() {
        if self.leftView.segmentedControl.selectedSegment == 1 {
            
        } else {
            self.leftView.segmentedControl.selectedSegment = 1
        }
    }
    
    func updateThumbnail(at index: Int) {
        if index < self.thumbnails.count {
            self.thumbnails[index].dirty = true
            self.thumbnailTableView.reloadData(forRowIndexes: IndexSet(integer: index), columnIndexes: IndexSet(integer: 0))
            
            if index < self.thumbnailTableView.numberOfRows {
                let thumbailTabCell = self.thumbnailTableView.view(atColumn: 0, row: index, makeIfNecessary: true) as? KMThumbnailTableviewCell
                thumbailTabCell?.pageView.updateThumbnial(needReset: true)
            }
            /*
             原问题:CrashKit - SKMainWindowController updateThumbnailAtPageIndex:] ([__NSArrayM objectAtIndex:]: index 9223372036854775807 beyond bounds [0 .. 17])
             注释原因:缩略图高亮为自定义后,刷新会将高亮刷新到0行
             */
    //        [leftSideController.thumbnailTableView reloadData];
//            BOOL visible = NO;
//            PDFPage *page = [[pdfView document] pageAtIndex:anIndex];
//            if([self.pdfView.visiblePages containsObject:page]) {
//                visible = YES;
//            }
//            NSInteger curIndex = [pdfView.document indexForPage:pdfView.currentPage];
//            if (need && curIndex != anIndex && !visible) {
//                [pdfView goToPage:[[pdfView document] pageAtIndex:anIndex]];
//            }
        }
    }
    
    func allThumbnailsNeedUpdate() {
        for thumb in self.thumbnails {
            thumb.dirty = true
        }
        self.reloadThumbnailSize()
    }
    
    func thumb_selectRowIndexsIfNeed(_ indexs: IndexSet) {
        let isReadMode = self.mainViewController?.isReadMode ?? false
        if self.type.methodType != .Thumbnail && isReadMode == false {
//            return
        }
        
        if indexs.isEmpty {
            return
        }
        
        Task { @MainActor in
            self.stopRepeatLoad = true
            self.thumbnailTableView.selectRowIndexes(indexs, byExtendingSelection: false)
            self.stopRepeatLoad = false
            self.thumbnailTableView.scrollRowToVisible(indexs.first ?? 0)
        }
    }
    
    func thumb_initSubViews() {
        self.thumbnailZoomInButton.target = self
        self.thumbnailZoomInButton.action = #selector(thumbnailSizeScaling)
        self.thumbnailZoomInButton.tag = 1
        self.thumbnailZoomOutButton.target = self
        self.thumbnailZoomOutButton.action = #selector(thumbnailSizeScaling)
        self.thumbnailZoomOutButton.tag = 0
        
        self.thumbnailTableView.delegate = self
        self.thumbnailTableView.dataSource = self
        self.thumbnailTableView.thumbDelegate = self
        self.thumbnailTableView.botaDelegate = self
        self.thumbnailTableView.menu?.delegate = self
        self.thumbnailTableView.registerForDraggedTypes([.localDraggedTypes, .fileURL,.string,.pdf])
        self.thumbnailTableView.registerForDraggedTypes(NSFilePromiseReceiver.readableDraggedTypes.map { NSPasteboard.PasteboardType($0) })
        self.thumbnailTableView.setDraggingSourceOperationMask(.every, forLocal: false)
    }
    
    func thumb_initDefalutValue() {
        self.isDisplayPageSize = KMDataManager.ud_bool(forKey: Self.Key.thumbDisplayPageSizeKey)
        
        self.thumbnailView.wantsLayer = true
        self.thumbnailView.layer?.backgroundColor = KMAppearance.Layout.l0Color().cgColor
        
        self.thumbnailTitleLabel.stringValue = KMLocalizedString("Thumbnails", nil)
        self.thumbnailTitleLabel.textColor = KMAppearance.Layout.h0Color()
        
        self.thumbnailZoomInButton.toolTip = KMLocalizedString("Zoom In", nil)
        self.thumbnailZoomOutButton.toolTip = KMLocalizedString("Zoom Out", nil)
        
        self.thumbnailTableView.backgroundColor = KMAppearance.Layout.l0Color()
        self.thumbnailTableView.allowsMultipleSelection = true
        self.thumbnailTableView.selectionHighlightStyle = .none
    }
    
    func thumb_fetchSelectedRows() -> [Int]? {
        return self.thumbnailTableView.selectedRowIndexes.sorted()
    }
    
    func updateThumbnailSelection() {
        let pageIndex = self.currentPageIndex()
        self.updatingThumbnailSelection = true
        self.thumbnailTableView.km_safe_selectRowIndexes(IndexSet(integer: pageIndex), byExtendingSelection: false)
        self.thumbnailTableView.scrollRowToVisible(pageIndex)
        self.updatingThumbnailSelection = false
    }
}

// MARK: - Others

extension KMLeftSideViewController {}

// MARK: - KMThumbnailTableViewDelegate

extension KMLeftSideViewController: KMThumbnailTableViewDelegate {
    func tableView(_ tableView: NSTableView, highlightLevelForRow row: Int) -> UInt {
        if tableView.isEqual(to: self.thumbnailTableView) {
//            NSUInteger i, iMax = [lastViewedPages count];
//            for (i = 0; i < iMax; i++) {
//                if (row == (NSInteger)[lastViewedPages pointerAtIndex:i])
//                    return i;
//            }
        }
        return UInt.max
    }
    
    func tableView(_ tableView: NSTableView, commandSelectRow rowIndex: Int) -> Bool {
        if tableView.isEqual(to: self.thumbnailTableView) {
    //        NSRect rect = [[[pdfView document] pageAtIndex:row] boundsForBox:kPDFDisplayBoxCropBox];
    //
    //        rect.origin.y = NSMidY(rect) - 0.5 * SNAPSHOT_HEIGHT;
    //        rect.size.height = SNAPSHOT_HEIGHT;
    //        [self showSnapshotAtPageNumber:row forRect:rect scaleFactor:[pdfView scaleFactor] autoFits:NO];
            let thumbailTabCell = tableView.view(atColumn: 0, row: rowIndex, makeIfNecessary: true) as? KMThumbnailTableviewCell
            thumbailTabCell?.isSelectCell = true
            var rowIndexSet = IndexSet()
            for i in self.thumbnailTableView.selectedRowIndexes {
                rowIndexSet.insert(i)
            }
            rowIndexSet.insert(rowIndex)
            self.thumbnailTableView.selectRowIndexes(rowIndexSet, byExtendingSelection: true)
            return true
        }
        return false
    }
    
    func tableView(_ tableView: NSTableView, shiftSelectRow rowIndex: Int) -> Bool {
        if tableView.isEqual(to: self.thumbnailTableView) {
            if (self.thumbnailTableView.selectedRowIndexes.count == 0) {
                let thumbailTabCell = tableView.view(atColumn: 0, row: rowIndex, makeIfNecessary: true) as? KMThumbnailTableviewCell
                thumbailTabCell?.isSelectCell = true
                var rowIndexSet = IndexSet()
                self.thumbnailTableView.selectRowIndexes(rowIndexSet, byExtendingSelection: true)
                return true
            } else if (self.thumbnailTableView.selectedRowIndexes.count == 1 && self.thumbnailTableView.selectedRowIndexes.first == rowIndex) {
                return false
            } else {
                var fristIndex = self.thumbnailTableView.selectedRowIndexes.first ?? Int.min
                var lastIndex = self.thumbnailTableView.selectedRowIndexes.last ?? Int.max
                for idx in self.thumbnailTableView.selectedRowIndexes {
                    if(idx < fristIndex) {
                        fristIndex = idx
                    }
                    if(idx > lastIndex) {
                        lastIndex = idx
                    }
                }
                
                if(rowIndex < fristIndex) {
                    fristIndex = rowIndex
                } else if (rowIndex > lastIndex) {
                    lastIndex = rowIndex
                }
                var rowIndexSet = IndexSet()
                for i in fristIndex ... lastIndex {
                    rowIndexSet.insert(i)
                }
                self.thumbnailTableView.selectRowIndexes(rowIndexSet, byExtendingSelection: true)
                self.thumbnailTableView.ks_reloadData()
                return true
            }
        }
        return false
    }
}

// MARK: - Undo & Redo

extension KMLeftSideViewController {
    @objc dynamic func tableView(_ tv: NSTableView, rotateRowsWithIndexes rowIndexes: NSIndexSet) {
        if tv.isEqual(to: self.thumbnailTableView) {
            for idx in rowIndexes {
                if (idx != NSNotFound) {
                    let page = self.pdfDocument()?.page(at: UInt(idx))
                    (self.listView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject).rotatePage(page, pageAt: idx)
                    page?.rightRotate()
                    self.layoutDocumentView()
                    self.resetThumbnails()
//                    NSInteger pageIndex = MIN(idx, [[pdfView document] pageCount]-1);
//                    [pdfView goToPage:[[pdfView document] pageAtIndex:pageIndex]];
                }
                self.thumbnailTableView.selectRowIndexes(rowIndexes as IndexSet, byExtendingSelection: true)
            }
        }
    }
 
    @objc dynamic func rotatePage(_ page: CPDFPage?, pageAt index: Int) {
        (self.listView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject).tableView(self.thumbnailTableView, rotateRowsWithIndexes: NSIndexSet(index: index))

        page?.leftRotate()
        self.layoutDocumentView()
        self.resetThumbnails()
    }
    
    @objc dynamic func insertPage(_ page: CPDFPage, pageAt index: Int) {
        (self.listView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject)._undo_removePage(page, at: index)
        self.pdfDocument()?.insertPageObject(page, at: UInt(index))
        self.layoutDocumentView()
        self.resetThumbnails(ks: false)
        let pageIndex = min(index, self.pageCount()-1)
        Task { @MainActor in
            self.listView?.go(toPageIndex: pageIndex, animated: false)
        }
    }
    
    @objc private func _undo_removePage(_ page: CPDFPage, at idx: Int) {
        self.tableView(self.thumbnailTableView, deleteRowsWithIndexes: IndexSet(integer: idx))
    }
    
    @objc dynamic func insertPages(_ selectedIndexSet: IndexSet, pageAt index: Int) {
        (self.listView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject).deletePages(selectedIndexSet, pageAt: index)
        self.layoutDocumentView()
        self.resetThumbnails(ks: false)
        
        Task { @MainActor in
            if let pageIndex = selectedIndexSet.first {
                self.listView?.go(toPageIndex: pageIndex, animated: false)
            }
        }
    }
    
    @objc dynamic func deletePages(_ selectedIndexSet: IndexSet, pageAt index: Int) {
        (self.listView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject).insertPages(selectedIndexSet, pageAt: index)
        
        for idx in selectedIndexSet {
            if idx < self.pageCount() {
                self.pdfDocument()?.removePage(at: UInt(idx))
            }
        }
        
        self.layoutDocumentView()
        self.resetThumbnails()
        let pageIndex = min(index, self.pageCount()-1)
        self.listView?.go(toPageIndex: pageIndex, animated: false)
    }
}

// MARK: - Menu Actions

extension KMLeftSideViewController {
    @objc func cutPage(_ sender: AnyObject?) {
        if KMMemberInfo.shared.isMemberAllFunction == false {
            KMMemberInfo.shared.advancedFunctionUsage()
            return
        }
        self.tableView(self.thumbnailTableView, cutRowsWithIndexes: self.thumbnailTableView.selectedRowIndexes)
    }
    
    @objc func copyPage(_ sender: AnyObject?) {
        self.tableView(self.thumbnailTableView, copyRowsWithIndexes: self.thumbnailTableView.selectedRowIndexes)
    }
    
    @objc func pastePage(_ sender: AnyObject?) {
        self.tableView(self.thumbnailTableView, pasteFromPasteboard: nil)
    }
    
    @objc func deletePage(_ sender: AnyObject?) {
        if KMMemberInfo.shared.isMemberAllFunction == false {
            KMMemberInfo.shared.advancedFunctionUsage()
            return
        }
        self.tableView(self.thumbnailTableView, deleteRowsWithIndexes: self.thumbnailTableView.selectedRowIndexes)
    }
    
    @objc func rotatePageMenuAction(_ sender: AnyObject?) {
        if KMMemberInfo.shared.isMemberAllFunction == false {
            KMMemberInfo.shared.advancedFunctionUsage()
            return
        }
        self.tableView(self.thumbnailTableView, rotateRowsWithIndexes: self.thumbnailTableView.selectedRowIndexes as NSIndexSet)
    }
    
    @objc func quickInsert(_ sender: AnyObject?) {
        if KMMemberInfo.shared.isMemberAllFunction == false {
            KMMemberInfo.shared.advancedFunctionUsage()
            return
        }
        let idx = self.thumbnailTableView.selectedRowIndexes.first ?? NSNotFound
        if idx == NSNotFound || idx >= self.pageCount() {
            return
        }
        let result = self.listView?.insertPage(KMNormalBlankSize, at: idx+1) ?? false
        if result == false {
            return
        }
        
        var selectedIndexSet = IndexSet()
        selectedIndexSet.insert(idx+1)
        self.insertPages(selectedIndexSet, pageAt: idx)
    }
    
    @objc func insert(_ sender: AnyObject?) {
        if KMMemberInfo.shared.isMemberAllFunction == false {
            KMMemberInfo.shared.advancedFunctionUsage()
            return
        }
        guard let document = self.pdfDocument() else {
            return
        }
        let idx = self.thumbnailTableView.selectedRowIndexes.first ?? NSNotFound
        if idx == NSNotFound || idx >= document.pageCount {
            return
        }
        if document.allowsCopying == false || document.allowsPrinting == false {
            Task {
                _ = await KMAlertTool.runModel(message: KMLocalizedString("This is a secured document. Editing is not permitted.", nil))
            }
            return
        }

        let winC = KMPDFEditInsertBlankPageWindow(document: document)
        winC.insertLocation = 3
        winC.currentPage = idx + 1
        winC.callback = { [weak self] pdfDoc, _, pages, insertI in
            guard let myWinC = self?.kmCurrentWindowC as? KMPDFEditInsertBlankPageWindow else {
                self?.km_quick_endSheet()
                return
            }
            if let _ = pages {
                var pageSize = myWinC.pageSize
                let direction = myWinC.pageRotation == 0 ? 0 : 1
                if (direction == 0) { // 纵向
                    if (pageSize.width > pageSize.height) { // 需要交换
                        let tmp = pageSize.width
                        pageSize.width = pageSize.height
                        pageSize.height = tmp
                    } else {
                        // no things.
                    }
                } else { // 横向
                    if (pageSize.width > pageSize.height) {
                        // no things.
                    } else { // 需要交换
                        let tmp = pageSize.width
                        pageSize.width = pageSize.height
                        pageSize.height = tmp
                    }
                }

                /// 插入位置
                let document = CPDFDocument()
                document?.insertPage(pageSize, at: 0)
                if let page = document?.page(at: 0) {
                    self?.insertPage(page, pageAt: insertI)
                }
            }
            self?.km_quick_endSheet()
        }
        self.km_beginSheet(windowC: winC)
    }
    
    @objc func insertPDF(_ sender: AnyObject?) {
        if KMMemberInfo.shared.isMemberAllFunction == false {
            KMMemberInfo.shared.advancedFunctionUsage()
            return
        }
                
        guard let document = self.pdfDocument() else {
            return
        }

        let idx = self.thumbnailTableView.selectedRowIndexes.first ?? NSNotFound
        if idx == NSNotFound || idx >= document.pageCount {
            return
        }
                
        if document.allowsCopying == false || document.allowsPrinting == false {
            Task {
                _ = await KMAlertTool.runModel(message: KMLocalizedString("This is a secured document. Editing is not permitted.", nil))
            }
            return
        }
        
        let panel = NSOpenPanel()
        panel.allowedFileTypes = ["pdf"]
        panel.beginSheetModal(for: self.view.window!) { response in
            if response == .cancel {
                return
            }
            
            for fileURL in panel.urls {
                let pdfDoc = CPDFDocument(url: fileURL)
                if let data = pdfDoc?.isLocked, data {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                        KMBaseWindowController.checkPassword(url: fileURL, type: .owner) { [unowned self] success, resultPassword in
                            if (resultPassword.isEmpty == false) {
                                let insertVC = KMPDFEditInsertPageWindow(document: document, path: fileURL, password: resultPassword)
                                insertVC.insertLocation = 3
                                insertVC.currentPage = idx + 1
                                self.km_beginSheet(windowC: insertVC)
                                insertVC.callback = { [weak self] pdfDoc, pwd, pages, insertIdx in
                                    var indexs = IndexSet()
                                    guard let _winC = self?.kmCurrentWindowC as? KMPDFEditInsertPageWindow, _winC.insertDocument != nil else {
                                        self?.km_quick_endSheet()
                                        return
                                    }
                                    let doc = _winC.insertDocument!
//                                    self?.model.insertedDocument = doc
                                    self?.model.insertedDocumentSet.insert(doc)
                                    let fileAttribute = _winC.fileAttribute
                                    var insertIndex = insertIdx
                                    var insertPages: [CPDFPage] = []
                                    for number in fileAttribute.fetchSelectPages() {
                                        if let page = doc.page(at: UInt(number-1)) {
                                            insertPages.append(page)
                                            indexs.insert(insertIndex)
                                            insertIndex += 1
                                        }
                                    }
                                    for (i, page) in insertPages.enumerated() {
                                        self?.pdfDocument()?.insertPageObject(page, at: UInt(insertIdx + i))
                                    }
                                    self?.insertPages(indexs, pageAt: insertIdx)
                                    self?.km_quick_endSheet()
                                }
                            }
                        }
                    }
                } else {
                    let insertVC = KMPDFEditInsertPageWindow(document: document, path: fileURL)
                    insertVC.insertLocation = 3
                    insertVC.currentPage = idx + 1
                    self.km_beginSheet(windowC: insertVC)
                    insertVC.callback = { [weak self] pdfDoc, pwd, pages, insertIdx in
                        var indexs = IndexSet()
                        guard let _winC = self?.kmCurrentWindowC as? KMPDFEditInsertPageWindow, _winC.insertDocument != nil else {
                            self?.km_quick_endSheet()
                            return
                        }
                        let doc = _winC.insertDocument!
//                        self?.model.insertedDocument = doc
                        self?.model.insertedDocumentSet.insert(doc)
                        let fileAttribute = _winC.fileAttribute
                        var insertIndex = insertIdx
                        var insertPages: [CPDFPage] = []
                        for number in fileAttribute.fetchSelectPages() {
                            if let page = doc.page(at: UInt(number-1)) {
                                insertPages.append(page)
                                indexs.insert(insertIndex)
                                insertIndex += 1
                            }
                        }
                        for (i, page) in insertPages.enumerated() {
                            self?.pdfDocument()?.insertPageObject(page, at: UInt(insertIdx + i))
                        }
                        self?.insertPages(indexs, pageAt: insertIdx)
                        self?.km_quick_endSheet()
                    }
                    
                }
            }
        }
    }
    
    @objc func extractPage(_ sender: AnyObject?) {
        if KMMemberInfo.shared.isMemberAllFunction == false {
            KMMemberInfo.shared.advancedFunctionUsage()
            return
        }
        self.tableView(self.thumbnailTableView, extractRowsWithIndexes: self.thumbnailTableView.selectedRowIndexes)
    }
    
    @objc func pageEdit(_ sender: AnyObject?) {
        self.delegate?.controller?(controller: self, itemClick: nil, itemKey: .pageEdit, params: nil)
    }
    
    @objc func displayPageSize(_ sender: AnyObject?) {
        if KMMemberInfo.shared.isMemberAllFunction == false {
            KMMemberInfo.shared.advancedFunctionUsage()
            return
        }

        self.isDisplayPageSize = !self.isDisplayPageSize
        KMDataManager.ud_set(self.isDisplayPageSize, forKey: Self.Key.thumbDisplayPageSizeKey)
        
        Task { @MainActor in
            self.thumbnailTableView.ks_reloadData()
        }
    }
    
    @objc func sharePage(_ sender: AnyObject?) {
        if KMMemberInfo.shared.isMemberAllFunction == false {
            KMMemberInfo.shared.advancedFunctionUsage()
            return
        }
        
        guard let document = self.pdfDocument() else {
            KMPrint("document is nil.", beep: true)
            return
        }
        let ris = self.thumbnailTableView.selectedRowIndexes
        if ris.isEmpty {
            KMPrint("empty selection.", beep: true)
            return
        }
        
        let pdf = CPDFDocument()
        pdf?.importPages(ris, from: document, at: 0)

        var fileName = self.fileNameWithSelectedPages(ris)
        if (fileName.count > 50) {
            fileName = fileName.substring(to: 50)
        }

        let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
        var cachesDir = paths.first ?? ""
        cachesDir = "\(cachesDir)/\(fileName).pdf"
        let url = URL(fileURLWithPath: cachesDir)
        let winC = KMProgressWindowController()
        self.km_beginSheet(windowC: winC) { resp, obj in }

        DispatchQueue.global().async {
            let sucess = pdf?.write(toFile: cachesDir) ?? false
            if (sucess) {
                DispatchQueue.main.async {
                    let represent = (sender as? NSMenuItem)?.representedObject as? NSSharingService
                    represent?.perform(withItems: [url])
                    
                    self.km_quick_endSheet()
                    winC.close()
                }
            } else {
                self.km_quick_endSheet()
                winC.close()
            }
        }
    }
}