//
//  Arrow.swift
//  MVMCoreUI
//
//  Created by Kevin Christiano on 2/20/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import UIKit


open class Arrow: View {
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    
    var arrowLayer = CAShapeLayer()
    
    public var arrowModel: ArrowModel? {
        return model as? ArrowModel
    }
    
    public var direction: ArrowModel.Direction {
        get { return ArrowModel.Direction(rawValue: degrees) ?? .right}
        set { degrees = newValue.rawValue }
    }
    
    open var isEnabled: Bool = true {
        didSet {
            arrowModel?.enabled = isEnabled
            isUserInteractionEnabled = isEnabled
            if isEnabled != oldValue {
                setNeedsDisplay()
            }
        }
    }
    
    open var disabledColor: UIColor {
        get { return arrowModel?.disabledColor.uiColor ?? .mvmCoolGray3 }
        set { arrowModel?.disabledColor = Color(uiColor: newValue) }
    }
    
    open var color: UIColor {
        get {
            guard let model = arrowModel else { return .mvmBlack }
            return model.inverted ? model.color_inverted.uiColor : model.color.uiColor
        }
        set {
            if let model = arrowModel, model.inverted {
                model.color_inverted = Color(uiColor: newValue)
            } else {
                arrowModel?.color = Color(uiColor: newValue)
            }
        }
    }
    
    open var degrees: Float {
        get { return arrowModel?.degrees ?? 0 }
        set { arrowModel?.degrees = newValue }
    }
    
    open var lineWidth: CGFloat {
        get { return arrowModel?.lineWidth ?? 1 }
        set { arrowModel?.lineWidth = newValue }
    }
    
    //--------------------------------------------------
    // MARK: - Constraints
    //--------------------------------------------------
    
    public var heightConstraint: NSLayoutConstraint?
    public var widthConstraint: NSLayoutConstraint?
    
    public func pinHeightAndWidth(constant: CGFloat = 12) {
        
        heightConstraint = heightAnchor.constraint(equalToConstant: constant)
        widthConstraint = widthAnchor.constraint(equalToConstant: constant)
        heightConstraint?.isActive = true
        widthConstraint?.isActive = true
    }
    
    //--------------------------------------------------
    // MARK: - Lifecycle
    //--------------------------------------------------
    
    open override func setupView() {
        super.setupView()
        
        drawShapeLayer()
        isOpaque = false
        layer.addSublayer(arrowLayer)
        arrowLayer.strokeEnd = 1
    }
    
    //--------------------------------------------------
    // MARK: - Drawing
    //--------------------------------------------------
    
    /// Draws the arrow pointing to the right and then rotates the arrow x degrees counter-clockwise.
    open override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        arrowLayer.transform = CATransform3DIdentity
        drawShapeLayer()
        
        let radians = CGFloat(degrees * Float.pi / 180)
        arrowLayer.transform = CATransform3DMakeRotation(-radians, 0, 0, 1)
    }
    
    private func drawShapeLayer() {
        
        arrowLayer.frame = bounds
        arrowLayer.strokeColor = isEnabled ? color.cgColor : disabledColor.cgColor
        arrowLayer.fillColor = UIColor.clear.cgColor
        arrowLayer.path = arrowPath()
        arrowLayer.lineJoin = .miter
        arrowLayer.lineCap = .butt
        arrowLayer.lineWidth = lineWidth
    }
    
    private func arrowPath() -> CGPath {
        
        let length = max(bounds.size.height, bounds.size.width)
        let inset = lineWidth / 2
        let midLength = length / 2
        
        var startPoint = CGPoint(x: midLength, y: inset)
        let pivotPoint = CGPoint(x: length - inset, y: midLength)
        var endPoint = CGPoint(x: midLength, y: length - inset)
        
        let bezierPath = UIBezierPath()
        bezierPath.move(to: startPoint)
        bezierPath.addLine(to: pivotPoint)
        bezierPath.addLine(to: endPoint)
        
        startPoint = CGPoint(x: inset, y: midLength)
        endPoint = CGPoint(x: length - inset, y: midLength)
        
        bezierPath.move(to: startPoint)
        bezierPath.addLine(to: pivotPoint)
        
        return bezierPath.cgPath
    }
    
    //--------------------------------------------------
    // MARK: - MoleculeViewProtocol
    //--------------------------------------------------
    
    public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.set(with: model, delegateObject, additionalData)
        
        guard let model = model as? ArrowModel else { return }
        
        isEnabled = model.enabled
        pinHeightAndWidth(constant: max(model.height, model.width))
    }
}
