import Foundation
import UIKit
import Display

final class SemanticStatusNodeCheckContext: SemanticStatusNodeStateContext {
    final class DrawingState: NSObject, SemanticStatusNodeStateDrawingState {
        let transitionFraction: CGFloat
        let value: CGFloat
        let appearance: SemanticStatusNodeState.CheckAppearance?
        
        init(transitionFraction: CGFloat, value: CGFloat, appearance: SemanticStatusNodeState.CheckAppearance?) {
            self.transitionFraction = transitionFraction
            self.value = value
            self.appearance = appearance
            
            super.init()
        }
        
        func draw(context: CGContext, size: CGSize, foregroundColor: UIColor) {
            let diameter = size.width
            
            let factor = diameter / 50.0
            
            context.saveGState()
            
            if foregroundColor.alpha.isZero {
                context.setBlendMode(.destinationOut)
                context.setFillColor(UIColor(white: 0.0, alpha: self.transitionFraction).cgColor)
                context.setStrokeColor(UIColor(white: 0.0, alpha: self.transitionFraction).cgColor)
            } else {
                context.setBlendMode(.normal)
                context.setFillColor(foregroundColor.withAlphaComponent(foregroundColor.alpha * self.transitionFraction).cgColor)
                context.setStrokeColor(foregroundColor.withAlphaComponent(foregroundColor.alpha * self.transitionFraction).cgColor)
            }
            
            let center = CGPoint(x: diameter / 2.0, y: diameter / 2.0)
            
            let lineWidth: CGFloat
            if let appearance = self.appearance {
                lineWidth = appearance.lineWidth
            } else {
                lineWidth = max(1.6, 2.25 * factor)
            }
        
            context.setLineWidth(max(1.7, lineWidth * factor))
            context.setLineCap(.round)
            context.setLineJoin(.round)
            context.setMiterLimit(10.0)
            
            let progress = self.value
            let firstSegment: CGFloat = max(0.0, min(1.0, progress * 3.0))
            
            var s = CGPoint(x: center.x - 10.0 * factor, y: center.y + 1.0 * factor)
            var p1 = CGPoint(x: 7.0 * factor, y: 7.0 * factor)
            var p2 = CGPoint(x: 13.0 * factor, y: -15.0 * factor)
            
            if diameter < 36.0 {
                s = CGPoint(x: center.x - 7.0 * factor, y: center.y + 1.0 * factor)
                p1 = CGPoint(x: 4.5 * factor, y: 4.5 * factor)
                p2 = CGPoint(x: 10.0 * factor, y: -11.0 * factor)
            }
            
            if !firstSegment.isZero {
                if firstSegment < 1.0 {
                    context.move(to: CGPoint(x: s.x + p1.x * firstSegment, y: s.y + p1.y * firstSegment))
                    context.addLine(to: s)
                } else {
                    let secondSegment = (progress - 0.33) * 1.5
                    context.move(to: CGPoint(x: s.x + p1.x + p2.x * secondSegment, y: s.y + p1.y + p2.y * secondSegment))
                    context.addLine(to: CGPoint(x: s.x + p1.x, y: s.y + p1.y))
                    context.addLine(to: s)
                }
            }
            context.strokePath()
        }
    }
    
    var value: CGFloat
    let appearance: SemanticStatusNodeState.CheckAppearance?
    var transition: SemanticStatusNodeProgressTransition?
    
    var isAnimating: Bool {
        return true
    }
    
    var requestUpdate: () -> Void = {}
    
    init(value: CGFloat, appearance: SemanticStatusNodeState.CheckAppearance?) {
        self.value = value
        self.appearance = appearance
        
        self.animate()
    }
    
    func drawingState(transitionFraction: CGFloat) -> SemanticStatusNodeStateDrawingState {
        let timestamp = CACurrentMediaTime()
        
        let resolvedValue: CGFloat
        if let transition = self.transition {
            let (v, isCompleted) = transition.valueAt(timestamp: timestamp, actualValue: value)
            resolvedValue = v
            if isCompleted {
                self.transition = nil
            }
        } else {
            resolvedValue = value
        }
        return DrawingState(transitionFraction: transitionFraction, value: resolvedValue, appearance: self.appearance)
    }
    
    func maskView() -> UIView? {
        return nil
    }
    
    func animate() {
        guard self.value < 1.0 else {
            return
        }
        let timestamp = CACurrentMediaTime()
        self.value = 1.0
        self.transition = SemanticStatusNodeProgressTransition(beginTime: timestamp, initialValue: 0.0)
    }
}