import Foundation
import UIKit
import AsyncDisplayKit
import Display

private final class ZoomWheelNodeDrawingState: NSObject {
    let transition: CGFloat
    let reverse: Bool
    
    init(transition: CGFloat, reverse: Bool) {
        self.transition = transition
        self.reverse = reverse
        
        super.init()
    }
}

final class ZoomWheelNode: ASDisplayNode {
    class State: Equatable {
        let active: Bool
        
        init(active: Bool) {
            self.active = active
        }
        
        static func ==(lhs: State, rhs: State) -> Bool {
            if lhs.active != rhs.active {
                return false
            }
            return true
        }
    }
    
    private class TransitionContext {
        let startTime: Double
        let duration: Double
        let previousState: State
        
        init(startTime: Double, duration: Double, previousState: State) {
            self.startTime = startTime
            self.duration = duration
            self.previousState = previousState
        }
    }
    
    private var animator: ConstantDisplayLinkAnimator?
    
    private var hasState = false
    private var state: State = State(active: false)
    private var transitionContext: TransitionContext?
    
    override init() {
        super.init()
        
        self.isOpaque = false
    }
    
    func update(state: State, animated: Bool) {
        var animated = animated
        if !self.hasState {
            self.hasState = true
            animated = false
        }
        
        if self.state != state {
            let previousState = self.state
            self.state = state
            
            if animated {
                self.transitionContext = TransitionContext(startTime: CACurrentMediaTime(), duration: 0.18, previousState: previousState)
            }
            
            self.updateAnimations()
            self.setNeedsDisplay()
        }
    }
    
    private func updateAnimations() {
        var animate = false
        let timestamp = CACurrentMediaTime()
        
        if let transitionContext = self.transitionContext {
            if transitionContext.startTime + transitionContext.duration < timestamp {
                self.transitionContext = nil
            } else {
                animate = true
            }
        }
        
        if animate {
            let animator: ConstantDisplayLinkAnimator
            if let current = self.animator {
                animator = current
            } else {
                animator = ConstantDisplayLinkAnimator(update: { [weak self] in
                    self?.updateAnimations()
                })
                self.animator = animator
            }
            animator.isPaused = false
        } else {
            self.animator?.isPaused = true
        }
        
        self.setNeedsDisplay()
    }
    
    override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
        var transitionFraction: CGFloat = self.state.active ? 1.0 : 0.0
        
        var reverse = false
        if let transitionContext = self.transitionContext {
            let timestamp = CACurrentMediaTime()
            var t = CGFloat((timestamp - transitionContext.startTime) / transitionContext.duration)
            t = min(1.0, max(0.0, t))
            
            if transitionContext.previousState.active != self.state.active {
                transitionFraction = self.state.active ? t : 1.0 - t
                
                reverse = transitionContext.previousState.active
            }
        }
        
        return ZoomWheelNodeDrawingState(transition: transitionFraction, reverse: reverse)
    }
    
    @objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
        let context = UIGraphicsGetCurrentContext()!
        
        if !isRasterizing {
            context.setBlendMode(.copy)
            context.setFillColor(UIColor.clear.cgColor)
            context.fill(bounds)
        }
        
        guard let parameters = parameters as? ZoomWheelNodeDrawingState else {
            return
        }

        let color = UIColor(rgb: 0xffffff)
        context.setFillColor(color.cgColor)
        
        let clearLineWidth: CGFloat = 4.0
        let lineWidth: CGFloat = 1.0 + UIScreenPixel
            
        context.scaleBy(x: 2.5, y: 2.5)
        
        context.translateBy(x: 4.0, y: 3.0)
        let _ = try? drawSvgPath(context, path: "M14,8.335 C14.36727,8.335 14.665,8.632731 14.665,9 C14.665,11.903515 12.48064,14.296846 9.665603,14.626311 L9.665,16 C9.665,16.367269 9.367269,16.665 9,16.665 C8.666119,16.665 8.389708,16.418942 8.34221,16.098269 L8.335,16 L8.3354,14.626428 C5.519879,14.297415 3.335,11.90386 3.335,9 C3.335,8.632731 3.632731,8.335 4,8.335 C4.367269,8.335 4.665,8.632731 4.665,9 C4.665,11.394154 6.605846,13.335 9,13.335 C11.39415,13.335 13.335,11.394154 13.335,9 C13.335,8.632731 13.63273,8.335 14,8.335 Z ")
        
        let _ = try? drawSvgPath(context, path: "M9,2.5 C10.38071,2.5 11.5,3.61929 11.5,5 L11.5,9 C11.5,10.380712 10.38071,11.5 9,11.5 C7.619288,11.5 6.5,10.380712 6.5,9 L6.5,5 C6.5,3.61929 7.619288,2.5 9,2.5 Z ")
            
        context.translateBy(x: -4.0, y: -3.0)
                
        if parameters.transition > 0.0 {
            let startPoint: CGPoint
            let endPoint: CGPoint
            
            let origin = CGPoint(x: 9.0, y: 10.0 - UIScreenPixel)
            let length: CGFloat = 17.0
    
            if parameters.reverse {
                startPoint = CGPoint(x: origin.x + length * (1.0 - parameters.transition), y: origin.y + length * (1.0 - parameters.transition))
                endPoint = CGPoint(x: origin.x + length, y: origin.y + length)
            } else {
                startPoint = origin
                endPoint = CGPoint(x: origin.x + length * parameters.transition, y: origin.y + length * parameters.transition)
            }
        
            context.setBlendMode(.clear)
            context.setLineWidth(clearLineWidth)
            
            context.move(to: startPoint)
            context.addLine(to: endPoint)
            context.strokePath()
        
            context.setBlendMode(.normal)
            context.setStrokeColor(color.cgColor)
            context.setLineWidth(lineWidth)
            context.setLineCap(.round)
            context.setLineJoin(.round)
            
            context.move(to: startPoint)
            context.addLine(to: endPoint)
            context.strokePath()
        }
    }
}

private class ButtonNode: HighlightTrackingButtonNode {
    private let backgroundNode: ASDisplayNode
    private let textNode: ImmediateTextNode
        
    init() {
        self.backgroundNode = ASDisplayNode()
        self.textNode = ImmediateTextNode()
        
        super.init()
        
        self.addSubnode(self.backgroundNode)
        self.addSubnode(self.textNode)
        
        self.highligthedChanged = { [weak self] highlight in
            if let strongSelf = self {
                
            }
        }
    }
    
    func update() {
        
    }
}

final class CameraZoomNode: ASDisplayNode {
    private let wheelNode: ZoomWheelNode
    
    private let backgroundNode: ASDisplayNode
    
    override init() {
        self.wheelNode = ZoomWheelNode()
        self.backgroundNode = ASDisplayNode()
        super.init()
        
        self.addSubnode(self.wheelNode)
    }
}