import Foundation
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import TelegramPresentationData
import WallpaperBackgroundNode

final class ChatHistoryNavigationButtons: ASDisplayNode {
    struct ButtonState: Equatable {
        var isEnabled: Bool
        
        init(isEnabled: Bool) {
            self.isEnabled = isEnabled
        }
    }
    
    struct DirectionState: Equatable {
        var up: ButtonState?
        var down: ButtonState?
        
        init(up: ButtonState?, down: ButtonState?) {
            self.up = up
            self.down = down
        }
    }
    
    private var theme: PresentationTheme
    private var dateTimeFormat: PresentationDateTimeFormat
    private let isChatRotated: Bool
    
    let reactionsButton: ChatHistoryNavigationButtonNode
    let mentionsButton: ChatHistoryNavigationButtonNode
    let downButton: ChatHistoryNavigationButtonNode
    let upButton: ChatHistoryNavigationButtonNode
    
    var downPressed: (() -> Void)? {
        didSet {
            self.downButton.tapped = self.downPressed
        }
    }
    
    var upPressed: (() -> Void)? {
        didSet {
            self.upButton.tapped = self.upPressed
        }
    }
    
    var reactionsPressed: (() -> Void)?
    var mentionsPressed: (() -> Void)?
    
    var directionButtonState: DirectionState = DirectionState(up: nil, down: nil) {
        didSet {
            if oldValue != self.directionButtonState {
                let _ = self.updateLayout(transition: .animated(duration: 0.3, curve: .spring))
            }
        }
    }
    
    var unreadCount: Int32 = 0 {
        didSet {
            if self.unreadCount != 0 {
                self.downButton.badge = compactNumericCountString(Int(self.unreadCount), decimalSeparator: self.dateTimeFormat.decimalSeparator)
            } else {
                self.downButton.badge = ""
            }
        }
    }
    
    var mentionCount: Int32 = 0 {
        didSet {
            if self.mentionCount != 0 {
                self.mentionsButton.badge = compactNumericCountString(Int(self.mentionCount), decimalSeparator: self.dateTimeFormat.decimalSeparator)
            } else {
                self.mentionsButton.badge = ""
            }
            
            if (oldValue != 0) != (self.mentionCount != 0) {
                let _ = self.updateLayout(transition: .animated(duration: 0.3, curve: .spring))
            }
        }
    }
    
    var reactionsCount: Int32 = 0 {
        didSet {
            if self.reactionsCount != 0 {
                self.reactionsButton.badge = compactNumericCountString(Int(self.reactionsCount), decimalSeparator: self.dateTimeFormat.decimalSeparator)
            } else {
                self.reactionsButton.badge = ""
            }
            
            if (oldValue != 0) != (self.reactionsCount != 0) {
                let _ = self.updateLayout(transition: .animated(duration: 0.3, curve: .spring))
            }
        }
    }
    
    init(theme: PresentationTheme, dateTimeFormat: PresentationDateTimeFormat, backgroundNode: WallpaperBackgroundNode, isChatRotated: Bool) {
        self.isChatRotated = isChatRotated
        self.theme = theme
        self.dateTimeFormat = dateTimeFormat
        
        self.mentionsButton = ChatHistoryNavigationButtonNode(theme: theme, backgroundNode: backgroundNode, type: .mentions)
        self.mentionsButton.alpha = 0.0
        self.mentionsButton.isHidden = true
        
        self.reactionsButton = ChatHistoryNavigationButtonNode(theme: theme, backgroundNode: backgroundNode, type: .reactions)
        self.reactionsButton.alpha = 0.0
        self.reactionsButton.isHidden = true
        
        self.downButton = ChatHistoryNavigationButtonNode(theme: theme, backgroundNode: backgroundNode, type: isChatRotated ? .down : .up)
        self.downButton.alpha = 0.0
        self.downButton.isHidden = true
        
        self.upButton = ChatHistoryNavigationButtonNode(theme: theme, backgroundNode: backgroundNode, type: isChatRotated ? .up : .down)
        self.upButton.alpha = 0.0
        self.upButton.isHidden = true
        
        super.init()
        
        self.addSubnode(self.reactionsButton)
        self.addSubnode(self.mentionsButton)
        self.addSubnode(self.downButton)
        self.addSubnode(self.upButton)
        
        self.reactionsButton.tapped = { [weak self] in
            self?.reactionsPressed?()
        }
        
        self.mentionsButton.tapped = { [weak self] in
            self?.mentionsPressed?()
        }
        
        self.downButton.isGestureEnabled = false
        self.upButton.isGestureEnabled = false
    }
    
    override func didLoad() {
        super.didLoad()
    }
    
    func update(theme: PresentationTheme, dateTimeFormat: PresentationDateTimeFormat, backgroundNode: WallpaperBackgroundNode) {
        self.theme = theme
        self.dateTimeFormat = dateTimeFormat
        
        self.reactionsButton.updateTheme(theme: theme, backgroundNode: backgroundNode)
        self.mentionsButton.updateTheme(theme: theme, backgroundNode: backgroundNode)
        self.downButton.updateTheme(theme: theme, backgroundNode: backgroundNode)
        self.upButton.updateTheme(theme: theme, backgroundNode: backgroundNode)
    }
    
    private var absoluteRect: (CGRect, CGSize)?
    func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition) {
        self.absoluteRect = (rect, containerSize)
        
        var reactionsFrame = self.reactionsButton.frame
        reactionsFrame.origin.x += rect.minX
        reactionsFrame.origin.y += rect.minY
        self.reactionsButton.update(rect: reactionsFrame, within: containerSize, transition: transition)
        
        var mentionsFrame = self.mentionsButton.frame
        mentionsFrame.origin.x += rect.minX
        mentionsFrame.origin.y += rect.minY
        self.mentionsButton.update(rect: mentionsFrame, within: containerSize, transition: transition)
        
        var upFrame = self.upButton.frame
        upFrame.origin.x += rect.minX
        upFrame.origin.y += rect.minY
        self.upButton.update(rect: upFrame, within: containerSize, transition: transition)
        
        var downFrame = self.downButton.frame
        downFrame.origin.x += rect.minX
        downFrame.origin.y += rect.minY
        self.downButton.update(rect: downFrame, within: containerSize, transition: transition)
    }
    
    func updateLayout(transition: ContainedViewLayoutTransition) -> CGSize {
        let buttonSize = CGSize(width: 38.0, height: 38.0)
        let completeSize = CGSize(width: buttonSize.width, height: buttonSize.height * 2.0 + 12.0)
        var upOffset: CGFloat = 0.0
        var mentionsOffset: CGFloat = 0.0
        var reactionsOffset: CGFloat = 0.0
        
        if let down = self.directionButtonState.down {
            self.downButton.imageNode.alpha = down.isEnabled ? 1.0 : 0.5
            self.downButton.buttonNode.isEnabled = down.isEnabled
            
            mentionsOffset += buttonSize.height + 12.0
            upOffset += buttonSize.height + 12.0

            self.downButton.isHidden = false
            transition.updateAlpha(node: self.downButton, alpha: 1.0)
            transition.updateTransformScale(node: self.downButton, scale: 1.0)
        } else {
            transition.updateAlpha(node: self.downButton, alpha: 0.0, completion: { [weak self] completed in
                guard let strongSelf = self, completed else {
                    return
                }
                strongSelf.downButton.isHidden = true
            })
            transition.updateTransformScale(node: self.downButton, scale: 0.2)
        }
        
        if let up = self.directionButtonState.up {
            self.upButton.imageNode.alpha = up.isEnabled ? 1.0 : 0.5
            self.upButton.buttonNode.isEnabled = up.isEnabled
            
            mentionsOffset += buttonSize.height + 12.0

            self.upButton.isHidden = false
            transition.updateAlpha(node: self.upButton, alpha: 1.0)
            transition.updateTransformScale(node: self.upButton, scale: 1.0)
        } else {
            transition.updateAlpha(node: self.upButton, alpha: 0.0, completion: { [weak self] completed in
                guard let strongSelf = self, completed else {
                    return
                }
                strongSelf.upButton.isHidden = true
            })
            transition.updateTransformScale(node: self.upButton, scale: 0.2)
        }
        
        if self.mentionCount != 0 {
            reactionsOffset += buttonSize.height + 12.0
            
            self.mentionsButton.isHidden = false
            transition.updateAlpha(node: self.mentionsButton, alpha: 1.0)
            transition.updateTransformScale(node: self.mentionsButton, scale: 1.0)
        } else {
            transition.updateAlpha(node: self.mentionsButton, alpha: 0.0, completion: { [weak self] completed in
                guard let strongSelf = self, completed else {
                    return
                }
                strongSelf.mentionsButton.isHidden = true
            })
            transition.updateTransformScale(node: self.mentionsButton, scale: 0.2)
        }
        
        if self.reactionsCount != 0 {
            self.reactionsButton.isHidden = false
            transition.updateAlpha(node: self.reactionsButton, alpha: 1.0)
            transition.updateTransformScale(node: self.reactionsButton, scale: 1.0)
        } else {
            transition.updateAlpha(node: self.reactionsButton, alpha: 0.0, completion: { [weak self] completed in
                guard let strongSelf = self, completed else {
                    return
                }
                strongSelf.reactionsButton.isHidden = true
            })
            transition.updateTransformScale(node: self.reactionsButton, scale: 0.2)
        }
        
        if self.isChatRotated {
            transition.updatePosition(node: self.downButton, position: CGRect(origin: CGPoint(x: 0.0, y: completeSize.height - buttonSize.height), size: buttonSize).center)
            transition.updatePosition(node: self.upButton, position: CGRect(origin: CGPoint(x: 0.0, y: completeSize.height - buttonSize.height - upOffset), size: buttonSize).center)
            transition.updatePosition(node: self.mentionsButton, position: CGRect(origin: CGPoint(x: 0.0, y: completeSize.height - buttonSize.height - mentionsOffset), size: buttonSize).center)
            transition.updatePosition(node: self.reactionsButton, position: CGRect(origin: CGPoint(x: 0.0, y: completeSize.height - buttonSize.height - mentionsOffset - reactionsOffset), size: buttonSize).center)
        } else {
            transition.updatePosition(node: self.downButton, position: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: buttonSize).center)
            transition.updatePosition(node: self.upButton, position: CGRect(origin: CGPoint(x: 0.0, y: upOffset), size: buttonSize).center)
            transition.updatePosition(node: self.mentionsButton, position: CGRect(origin: CGPoint(x: 0.0, y: mentionsOffset), size: buttonSize).center)
            transition.updatePosition(node: self.reactionsButton, position: CGRect(origin: CGPoint(x: 0.0, y: mentionsOffset + reactionsOffset), size: buttonSize).center)
        }
        
        if let (rect, containerSize) = self.absoluteRect {
            self.update(rect: rect, within: containerSize, transition: transition)
        }
        
        return completeSize
    }
    
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if let subnodes = self.subnodes {
            for subnode in subnodes {
                if !subnode.isUserInteractionEnabled {
                    continue
                }
                if let result = subnode.hitTest(point.offsetBy(dx: -subnode.frame.minX, dy: -subnode.frame.minY), with: event) {
                    return result
                }
            }
        }
        return nil
    }

    final class SnapshotState {
        fileprivate let downButtonSnapshotView: UIView?

        fileprivate init(
            downButtonSnapshotView: UIView?
        ) {
            self.downButtonSnapshotView = downButtonSnapshotView
        }
    }

    func prepareSnapshotState() -> SnapshotState {
        var downButtonSnapshotView: UIView?
        if !self.downButton.isHidden {
            downButtonSnapshotView = self.downButton.view.snapshotView(afterScreenUpdates: false)!
        }
        return SnapshotState(
            downButtonSnapshotView: downButtonSnapshotView
        )
    }

    func animateFromSnapshot(_ snapshotState: SnapshotState) {
        if self.downButton.isHidden != (snapshotState.downButtonSnapshotView == nil) {
            if self.downButton.isHidden {
            } else {
                self.downButton.layer.animateAlpha(from: 0.0, to: self.downButton.alpha, duration: 0.3)
                self.downButton.layer.animateScale(from: 0.1, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: true)
            }
        }
    }
}