//
//  KMPDFSignatureImageView.swift
//  PDF Reader Pro
//
//  Created by lizhe on 2023/10/9.
//

import Cocoa
import Quartz

let KMSignatureMaxWidth = 400.0
let KMSignatureMaxHeight = 300.0

@objcMembers class KMPDFSignatureImageView: NSView {

    var picImage: NSImage?
    @IBOutlet var pictureView: NSView!
//    @IBOutlet var emptyTipLbl: NSTextField!
    @IBOutlet var dragButton: NSButton!
//    @IBOutlet var emptyImg: NSImageView!
    
    @IBOutlet var heraLabel: NSTextField!
    @IBOutlet var orLabel: NSTextField!
    
    var clearBackground: Bool = false {
        didSet {
            if let imageURL = imageURL, imageURL.path.count > 0 {
                loadImageViewPath(imageURL, isRemoveBGColor: clearBackground)
            }
        }
    }
    
    var trackingArea: NSTrackingArea?

    var imageURL: URL?
    
    var changeSignatureImageCallback: ((Bool) -> Void)?

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        wantsLayer = true
        layer?.borderWidth = 1.0
        layer?.borderColor = NSColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.05).cgColor
        layer?.backgroundColor = NSColor(red: 1, green: 1, blue: 1, alpha: 0.9).cgColor
        registerForDraggedTypes([.fileURL])
    }
    
    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        registerForDraggedTypes([.fileURL])
    }

    override func awakeFromNib() {
        super.awakeFromNib()
//        emptyTipLbl.stringValue = NSLocalizedString("Select image file", comment: "")
//        emptyTipLbl.textColor = .labelColor
        self.heraLabel.stringValue  = NSLocalizedString("Drop image here", comment: "")
        self.orLabel.stringValue = NSLocalizedString("or", comment: "")
        dragButton.title = NSLocalizedString("Select a File",  comment: "")
        dragButton.wantsLayer = true
        dragButton.setTitleColor(color: .labelColor, font: nil)
        pictureView.wantsLayer = true
//        emptyImg.image = NSImage(named: "signPicture_nor")

        trackingArea = NSTrackingArea(rect: bounds, options: [.mouseEnteredAndExited, .mouseMoved, .activeAlways], owner: self, userInfo: nil)
        if let trackingArea = trackingArea {
            addTrackingArea(trackingArea)
        }
    }

    func supportedImageTypes() -> [String] {
        return ["jpg", "cur", "bmp", "jpeg", "gif", "png", "tiff", "tif", "ico", "icns", "tga", "psd", "eps", "hdr", "jp2", "jpc", "pict", "sgi", "pdf"]
    }

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
        if let picImage = picImage {
            let selfSize = self.frame.size
            var rect = NSZeroRect
            if let imageCIImage = CIImage(data: picImage.tiffRepresentation!) {
                let size = imageCIImage.extent.size
                let scale = min((selfSize.width - 30) / size.width, (selfSize.height - 30) / size.height)
                if scale > 1 {
                    rect = NSRect(x: 0, y: 0, width: size.width, height: size.height)
                } else {
                    rect = NSRect(x: 0, y: 0, width: size.width * scale, height: size.height * scale)
                }
                picImage.draw(in: NSRect(x: (selfSize.width - rect.size.width) / 2, y: (selfSize.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height), from: NSZeroRect, operation: .sourceOver, fraction: 1.0)
            }
        }
    }

    func clearImage() {
        picImage = nil
        imageURL = nil
        pictureView.isHidden = false
//        emptyTipLbl.isHidden = false
        needsDisplay = true
    }

    func reSelectImage() {
        buttonItemClick_SelectPhoto(nil)
    }

    func signatureImage() -> NSImage? {
        var rect = CGRect.zero
        
        guard let picImage = self.picImage else {
            return nil
        }
        
        let imageCIImage = CIImage(data: picImage.tiffRepresentation!)
        let size = imageCIImage?.extent.size ?? CGSize.zero
        
        let scale = min(KMSignatureMaxWidth / size.width, KMSignatureMaxHeight / size.height)
        
        if scale > 1 {
            rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        } else {
            rect = CGRect(x: 0, y: 0, width: size.width * scale, height: size.height * scale)
        }
        
        let image = NSImage(size: rect.size)
        image.lockFocus()
        picImage.draw(in: rect, from: NSZeroRect, operation: .sourceOver, fraction: 1.0)
        image.unlockFocus()
        
        return image
    }

    func loadImageViewPath(_ url: URL, isRemoveBGColor: Bool) {
        self.imageURL = url
        let filePath: NSString = url.path as NSString
        
        if filePath.pathExtension.lowercased() == "pdf" {
            if let pdf = PDFDocument(url: url), pdf.isEncrypted {
                return
            }
        }
        
        if let image = NSImage(contentsOfFile: filePath as String) {
            if isRemoveBGColor {
//                if let imageData = image.tiffRepresentation {
//                    if let imageSource = CGImageSourceCreateWithData(imageData as CFData, nil),
//                       let imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) {
//                        
//                        let imageWidth = image.size.width
//                        let imageHeight = image.size.height
//                        let bytesPerRow = Int(imageWidth) * 4
//                        var rgbImageBuf = [UInt32](repeating: 0, count: Int(bytesPerRow) * Int(imageHeight))
//                        
//                        let colorSpace = CGColorSpaceCreateDeviceRGB()
//                        let imageRect = CGRect(x: 0.0, y: 0.0, width: imageWidth, height: imageHeight)
//                        
//                        if let context = CGContext(data: &rgbImageBuf,
//                                                   width: Int(imageWidth),
//                                                   height: Int(imageHeight),
//                                                   bitsPerComponent: 8,
//                                                   bytesPerRow: bytesPerRow,
//                                                   space: colorSpace,
//                                                   bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue),
//                           let dataProvider = CGDataProvider(dataInfo: nil,
//                                                             data: &rgbImageBuf,
//                                                             size: Int(bytesPerRow) * Int(imageHeight),
//                                                             releaseData: { (info, data, size) in
//                                                                 data.deallocate()
//                                                             }),
//                           let newImageRef = CGImage(width: Int(imageWidth),
//                                                     height: Int(imageHeight),
//                                                     bitsPerComponent: 8,
//                                                     bitsPerPixel: 32,
//                                                     bytesPerRow: bytesPerRow,
//                                                     space: colorSpace,
//                                                     bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue),
//                                                     provider: dataProvider,
//                                                     decode: nil,
//                                                     shouldInterpolate: true,
//                                                     intent: .defaultIntent) {
//                            
//                            let newImage = NSImage(size: CGSize(width: imageWidth, height: imageHeight))
//                            newImage.lockFocus()
//                            
//                            let imageContext = NSGraphicsContext(cgContext: context, flipped: false)
//                            NSGraphicsContext.current = imageContext
//                            context.draw(imageRef, in: imageRect)
//                            newImage.unlockFocus()
//                            self.picImage = newImage
//                            self.pictureView.isHidden = true
//                            self.emptyTipLbl.isHidden = true
//                            self.setNeedsDisplay(NSRect.zero)
//                            
//                        }
//                    }
//                }
                let resultImage = self.makeImageTransparent(image)
                self.picImage = resultImage
                self.pictureView.isHidden = true
//                self.emptyTipLbl.isHidden = true
                self.layer?.setNeedsDisplay()
                debugPrint("移除成功")
            } else {
                self.picImage = image
                self.pictureView.isHidden = true
//                self.emptyTipLbl.isHidden = true
                self.layer?.setNeedsDisplay()
            }
        }
    }
    
    func makeImageTransparent(_ inputImage: NSImage) -> NSImage? {
        if let cgImage = inputImage.cgImage(forProposedRect: nil, context: nil, hints: nil) {
            // 创建一个位图上下文,与图像大小相同
            let width = cgImage.width
            let height = cgImage.height
            
            let colorSpace = CGColorSpaceCreateDeviceRGB()
            let bytesPerPixel = 4
            let bytesPerRow = bytesPerPixel * width
            let bitsPerComponent = 8
            
            let context = CGContext(data: nil,
                                    width: width,
                                    height: height,
                                    bitsPerComponent: bitsPerComponent,
                                    bytesPerRow: bytesPerRow,
                                    space: colorSpace,
                                    bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
            
            // 绘制图像到上下文
            context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
            
            // 获取上下文中的像素数据
            if let data = context?.data {
                let buffer = data.bindMemory(to: UInt8.self, capacity: width * height * bytesPerPixel)
                
                // 迭代每个像素并将白色像素变为透明
                for y in 0..<height {
                    for x in 0..<width {
                        let pixelIndex = (y * width + x) * bytesPerPixel
                        let red = buffer[pixelIndex]
                        let green = buffer[pixelIndex + 1]
                        let blue = buffer[pixelIndex + 2]
                        
                        // 判断是否是白色像素(这里假设白色为红、绿和蓝都为255)
                        if red > 240 && green > 240 && blue > 240 {
                            // 将白色像素的 alpha 通道设为0,使其变为透明
                            buffer[pixelIndex + 3] = 0
                        }
                    }
                }
                
                // 创建新的 CGImage
                if let newCgImage = context?.makeImage() {
                    // 创建新的 NSImage
                    let newImage = NSImage(cgImage: newCgImage, size: inputImage.size)
                    return newImage
                    // 现在,newImage 包含具有白色像素变为透明的图像
                    // 可以将其显示在您的应用程序中或保存到磁盘上
                }
            }
        }
        return nil
    }

    func setGradualChanging() -> CAGradientLayer {
        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = dragButton.bounds
        gradientLayer.colors = [NSColor.lightGray.cgColor, NSColor.white.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0, y: 0)
        gradientLayer.endPoint = CGPoint(x: 1, y: 1)
        gradientLayer.locations = [0, 1]
        return gradientLayer
    }

    func isDamageImage(_ image: NSImage, imagePath: String) -> Bool {
        let addImageAnnotation = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last?.appending("/\(Bundle.main.bundleIdentifier!)") ?? ""

        if !FileManager.default.fileExists(atPath: addImageAnnotation) {
            try? FileManager.default.createDirectory(atPath: addImageAnnotation, withIntermediateDirectories: false, attributes: nil)
        }

        if let imageData = image.tiffRepresentation, let imageRep = NSBitmapImageRep(data: imageData) {
            imageRep.size = image.size
            var imageData: Data?

            if imagePath.lowercased() == "png" {
                imageData = imageRep.representation(using: .png, properties: [:])
            } else {
                imageData = imageRep.representation(using: .jpeg, properties: [:])
            }

            if let imageData = imageData, let tagString = tagString() {
                let rPath = (addImageAnnotation.stringByAppendingPathComponent(tagString)).stringByAppendingPathExtension("png")
                do {
                    try imageData.write(to: URL(fileURLWithPath: rPath))
//                    NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: "")
                    return false
                } catch {
                    return true
                }
            }
        }

        return false
    }

    func tagString() -> String? {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyMMddHHmmss"
        return String(format: "%@%04d", dateFormatter.string(from: Date()), Int(arc4random_uniform(10000)))
    }

    @IBAction func buttonItemClick_SelectPhoto(_ sender: Any?) {
        let openPanel = NSOpenPanel()
        openPanel.allowedFileTypes = supportedImageTypes()
        if let accessoryView = openPanel.accessoryView as? NSButton {
            accessoryView.state = UserDefaults.standard.bool(forKey: "AnnotationSelectPhoto") ? .on : .off
        }

        openPanel.allowsMultipleSelection = false
        openPanel.beginSheetModal(for: window ?? NSApp.mainWindow!) { [weak self] (result) in
            if result == .OK, let url = openPanel.url {
                // Check if the PDF file is damaged
                let filePath: NSString = url.path as NSString
                if filePath.pathExtension.lowercased() == "pdf" {
                    if let pdf = PDFDocument(url: url), !pdf.isEncrypted {
                        self?.loadImageViewPath(url, isRemoveBGColor: self?.clearBackground ?? false)
                        self?.changeSignatureImageCallback?(true)
                        return
                    } else {
                        let alert = NSAlert()
                        alert.alertStyle = .critical
                        alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
                        alert.runModal()
                        return
                    }
                }

                if let image = NSImage(contentsOfFile: url.path), self?.isDamageImage(image, imagePath: url.path) == true {
                    let alert = NSAlert()
                    alert.alertStyle = .critical
                    alert.messageText = String(format: NSLocalizedString("The file \"%@\" could not be opened.", comment: ""), url.path.lastPathComponent)
                    alert.informativeText = NSLocalizedString("It may be damaged or use a file format that PDF Reader Pro doesn’t recognize.", comment: "")
                    alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
                    alert.beginSheetModal(for: NSApp.mainWindow ?? NSApp.keyWindow!) { (returnCode) in
                        if returnCode == .alertFirstButtonReturn {

                        }
                    }
                    return
                }

                self?.loadImageViewPath(url, isRemoveBGColor: self?.clearBackground ?? false)
                self?.changeSignatureImageCallback?(true)
            }
        }
    }

    override func mouseEntered(with event: NSEvent) {
        super.mouseEntered(with: event)
//        emptyImg.image = NSImage(named: "signPicture_hover")
    }

    override func mouseMoved(with event: NSEvent) {
        super.mouseMoved(with: event)

        if let windowContentView = window?.contentView, let convertPoint = pictureView?.convert(event.locationInWindow, from: windowContentView) {
            if pictureView.bounds.contains(convertPoint) {
//                emptyImg.image = NSImage(named: "signPicture_hover")
            } else {
//                emptyImg.image = NSImage(named: "signPicture_nor")
            }
        }
    }

    override func mouseExited(with event: NSEvent) {
        super.mouseExited(with: event)
//        emptyImg.image = NSImage(named: "signPicture_nor")
    }

    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        let pboard = sender.draggingPasteboard
        if pboard.availableType(from: [.fileURL]) != nil {
            guard let pbItems = pboard.pasteboardItems else {
                return NSDragOperation(rawValue: 0)
            }
            for item in pbItems {
                guard let data = item.string(forType: .fileURL), let _url = URL(string: data) else {
                    continue
                }
                if supportedImageTypes().contains(_url.pathExtension.lowercased()) {
                    return .every
                }
            }
        }
        return []
    }

    override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
        let pboard = sender.draggingPasteboard
        if pboard.availableType(from: [.fileURL]) != nil {
            guard let pbItems = pboard.pasteboardItems else {
                return false
            }
            for item in pbItems {
                guard let data = item.string(forType: .fileURL), let _url = URL(string: data) else {
                    continue
                }
                if supportedImageTypes().contains(_url.pathExtension.lowercased()) {
                    loadImageViewPath(_url, isRemoveBGColor: clearBackground)
                    changeSignatureImageCallback?(true)
                    return true
                }
            }
        }
        return false
    }
}

private extension NSImage {
    func resized(to size: NSSize) -> NSImage {
        let image = NSImage(size: size)
        image.lockFocus()

        let ctx = NSGraphicsContext.current?.cgContext
        ctx?.interpolationQuality = .high

        draw(in: NSRect(origin: .zero, size: size), from: NSRect(origin: .zero, size: self.size), operation: .sourceOver, fraction: 1.0)

        image.unlockFocus()
        return image
    }
}