//
//  KMAnimatedBorderlessWindow.swift
//  PDF Reader Pro
//
//  Created by tangchao on 2023/11/23.
//

import Cocoa

@objcMembers class KMAnimatedBorderlessWindow: NSPanel {
    var defaultAlphaValue: CGFloat = 0
    var autoHideTimeInterval: TimeInterval = 0
    var fadeInDuration: TimeInterval {
        get {
            return FADE_IN_DURATION
        }
    }
    var fadeOutDuration: TimeInterval {
        get {
            return FADE_OUT_DURATION
        }
    }
    var backgroundImage: NSImage? {
        get {
            if let _ = self.contentView?.responds(to: NSSelectorFromString("image")) {
                return (self.contentView as? NSImageView)?.image
            }
            return nil
        }
        set {
            var imageView: NSImageView?
            if let data = self.contentView?.responds(to: NSSelectorFromString("setImage:")), data {
                imageView = self.contentView as? NSImageView
            } else if newValue != nil {
                imageView = NSImageView()
                imageView?.isEditable = false
                imageView?.imageFrameStyle = .none
                imageView?.imageScaling = .scaleProportionallyDown
                self.contentView = imageView
            }
            imageView?.image = newValue
        }
    }
    
    private let ALPHA_VALUE = 1.0
    private let FADE_IN_DURATION = 0.3
    private let FADE_OUT_DURATION = 1.0
    private let AUTO_HIDE_TIME_INTERVAL = 0.0
    
    deinit {
        KMPrint("KMAnimatedBorderlessWindow deinit.")
        
        self.stopAnimation()
    }
    
    convenience init(contentRect: NSRect) {
        self.init(contentRect: contentRect, styleMask: [.borderless], backing: .buffered, defer: false)
        
        self.defaultAlphaValue = ALPHA_VALUE
        self.autoHideTimeInterval = AUTO_HIDE_TIME_INTERVAL
        
        self.backgroundColor = .clear
        self.isOpaque = false
        self.alphaValue = self.defaultAlphaValue
        self.isReleasedWhenClosed = false
        self.hidesOnDeactivate = false
        if self.responds(to: NSSelectorFromString("setAnimationBehavior:")) {
            self.animationBehavior = .none
        }
    }
    
    override var canBecomeKey: Bool {
        return false
    }
    
    override var canBecomeMain: Bool {
        return false
    }
    
    override func accessibilityIsIgnored() -> Bool {
        return true
    }
    
    // MARK: - Public Methods
    
    public func fadeIn() {
        self.stopAnimation()
        
        if self.isVisible == false {
            self.alphaValue = 0.0
        }
        super.orderFront(self)
        
        if UserDefaults.standard.bool(forKey: SKDisableAnimationsKey) {
            self.alphaValue = self.defaultAlphaValue
        } else {
            NSAnimationContext.runAnimationGroup { context in
                context.duration = self.fadeInDuration
                self.animator().alphaValue = self.defaultAlphaValue
            }
        }
        self._fadeOutAfterTimeout()
    }
    
    @objc public func fadeOut() {
        self.stopAnimation()
        
        self.alphaValue = self.defaultAlphaValue
        
        if UserDefaults.standard.bool(forKey: SKDisableAnimationsKey) {
            self.remove()
        } else {
            NSAnimationContext.runAnimationGroup { context in
                context.duration = self.fadeOutDuration
                self.animator().alphaValue = 0.0
            }
            // don't put this in the completionHandler, because we want to be able to stop this using stopAnimation
            self.perform(#selector(remove), with: nil, afterDelay: self.fadeOutDuration)
        }
    }
    
    @objc public func remove() {
        self.orderOut(nil)
    }
    
    override func orderOut(_ sender: Any?) {
        self.stopAnimation()
        super.orderOut(sender)
        self.alphaValue = self.defaultAlphaValue
    }
    
    override func orderFront(_ sender: Any?) {
        self.stopAnimation()
        self.alphaValue = self.defaultAlphaValue
        super.orderFront(sender)
        self._fadeOutAfterTimeout()
    }
    
    override func orderFrontRegardless() {
        self.stopAnimation()
        self.alphaValue = self.defaultAlphaValue
        super.orderFrontRegardless()
        self._fadeOutAfterTimeout()
    }
    
    public func stopAnimation() {
        Self.cancelPreviousPerformRequests(withTarget: self, selector: #selector(fadeOut), object: nil)
        Self.cancelPreviousPerformRequests(withTarget: self, selector: #selector(remove), object: nil)
    }
}

// MARK: - Private Methods

extension KMAnimatedBorderlessWindow {
    private func _fadeOutAfterTimeout() {
        if self.autoHideTimeInterval > 0.0 {
            self.perform(#selector(fadeOut), with: nil, afterDelay: self.autoHideTimeInterval)
        }
    }
}