//
//  RadioBox.swift
//  MVMCoreUI
//
//  Created by Scott Pfeil on 4/9/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//


open class RadioBox: Control, MFButtonProtocol {
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    
    public let label = Label(fontStyle: .RegularBodySmall)
    public let subTextLabel = Label(fontStyle: .RegularMicro)
    public var isOutOfStock = false
    public var accentColor = UIColor.mvmRed

    public let innerPadding: CGFloat = 12.0
    
    private var borderLayer: CALayer?
    private var strikeLayer: CALayer?
    private var maskLayer: CALayer?
    
    public var subTextLabelHeightConstraint: NSLayoutConstraint?
    
    private var delegateObject: MVMCoreUIDelegateObject?
    var additionalData: [AnyHashable: Any]?
    
    public var radioBoxModel: RadioBoxModel? {
        model as? RadioBoxModel
    }
    
    public override var isSelected: Bool {
        didSet { updateAccessibility() }
    }
    
    public override var isEnabled: Bool {
        didSet { updateAccessibility() }
    }
        
    //--------------------------------------------------
    // MARK: - MVMCoreViewProtocol
    //--------------------------------------------------
    
    open override func updateView(_ size: CGFloat) {
        super.updateView(size)
        label.updateView(size)
        subTextLabel.updateView(size)
        layer.setNeedsDisplay()
    }
    
    open override func setupView() {
        super.setupView()
        
        layer.delegate = self
        layer.borderColor = UIColor.mvmCoolGray6.cgColor
        layer.borderWidth = 1

        label.numberOfLines = 1
        addSubview(label)
        NSLayoutConstraint.constraintPinSubview(label, pinTop: true, topConstant: innerPadding, pinBottom: false, bottomConstant: 0, pinLeft: true, leftConstant: innerPadding, pinRight: true, rightConstant: innerPadding)
        
        subTextLabel.textColor = .mvmCoolGray6
        subTextLabel.numberOfLines = 1
        addSubview(subTextLabel)
        NSLayoutConstraint.constraintPinSubview(subTextLabel, pinTop: false, topConstant:0, pinBottom: false, bottomConstant: 0, pinLeft: true, leftConstant: innerPadding, pinRight: true, rightConstant: innerPadding)
        bottomAnchor.constraint(greaterThanOrEqualTo: subTextLabel.bottomAnchor, constant: innerPadding).isActive = true
        subTextLabel.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 2).isActive = true
        subTextLabelHeightConstraint = subTextLabel.heightAnchor.constraint(equalToConstant: 0)
        subTextLabelHeightConstraint?.isActive = true
        
        addTarget(self, action: #selector(selectBox), for: .touchUpInside)
        
        isAccessibilityElement = true
    }
    
    open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.set(with: model, delegateObject, additionalData)
        guard let model = model as? RadioBoxModel else { return }
        self.delegateObject = delegateObject
        self.additionalData = additionalData
        label.text = model.text
        subTextLabel.text = model.subText
        isOutOfStock = model.strikethrough
        subTextLabelHeightConstraint?.isActive = (subTextLabel.text?.count ?? 0) == 0
        if let color = model.selectedAccentColor?.uiColor {
            accentColor = color
        }
        isSelected = model.selected
        isEnabled = model.enabled && !model.readOnly
    }
    
    open override func reset() {
        super.reset()
        backgroundColor = .white
        accentColor = .mvmRed
    }
    
    //--------------------------------------------------
    // MARK: - State Handling
    //--------------------------------------------------
    
    open override func draw(_ layer: CALayer, in ctx: CGContext) {
        // Draw the strikethrough
        strikeLayer?.removeFromSuperlayer()
        if isOutOfStock {
            let line = getStrikeThrough(color: isSelected ? .black : .mvmCoolGray6, thickness: 1)
            layer.addSublayer(line)
            strikeLayer = line
        }
        
        // Draw the border
        borderLayer?.removeFromSuperlayer()
        if isSelected {
            layer.borderWidth = 0
            let border = getSelectedBorder()
            layer.addSublayer(border)
            borderLayer = border
        } else {
            layer.borderWidth = 1
        }
        
        // Handle Mask
        maskLayer?.removeFromSuperlayer()
        if !isEnabled {
            let mask = getMaskLayer()
            layer.mask = mask
            maskLayer = mask
        }
    }
    
    open override func layoutSubviews() {
        super.layoutSubviews()
        // Accounts for any size changes
        layer.setNeedsDisplay()
    }
    
    @objc open func selectBox() {
        guard isEnabled, !isSelected else { return }
        isSelected = true
        radioBoxModel?.selected = isSelected
        if let radioBoxModel = radioBoxModel, let actionModel = radioBoxModel.action {
            Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioBoxModel)
        }
        layer.setNeedsDisplay()
    }
    
    @objc open func deselectBox() {
        isSelected = false
        radioBoxModel?.selected = isSelected
        layer.setNeedsDisplay()
    }
    
    /// Gets the selected state border
    func getSelectedBorder() -> CAShapeLayer {
        let layer = CAShapeLayer()
        
        let topLineWidth: CGFloat = 4
        let topLinePath = UIBezierPath()
        topLinePath.lineWidth = topLineWidth
        topLinePath.move(to: CGPoint(x: 0, y: topLineWidth / 2.0))
        topLinePath.addLine(to: CGPoint(x: bounds.width, y: topLineWidth / 2.0))
        
        let topLineLayer = CAShapeLayer()
        topLineLayer.fillColor = nil
        topLineLayer.strokeColor = accentColor.cgColor
        topLineLayer.lineWidth = 4
        topLineLayer.path = topLinePath.cgPath
        layer.addSublayer(topLineLayer)

        let lineWidth: CGFloat = 1
        let halfLineWidth: CGFloat = 0.5
        let linePath = UIBezierPath()
        linePath.move(to: CGPoint(x: halfLineWidth, y: topLineWidth))
        linePath.addLine(to: CGPoint(x: halfLineWidth, y: bounds.height))
        linePath.move(to: CGPoint(x: 0, y: bounds.height - halfLineWidth))
        linePath.addLine(to: CGPoint(x: bounds.width, y: bounds.height - halfLineWidth))
        linePath.move(to: CGPoint(x: bounds.width - halfLineWidth, y: bounds.height))
        linePath.addLine(to: CGPoint(x: bounds.width - halfLineWidth, y: topLineWidth))
        
        let borderLayer = CAShapeLayer()
        borderLayer.fillColor = nil
        borderLayer.strokeColor = UIColor.black.cgColor
        borderLayer.lineWidth = lineWidth
        borderLayer.path = linePath.cgPath
        layer.addSublayer(borderLayer)
       
        return layer
    }
    
    /// Adds a border to edge
    func getStrikeThrough(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
        let border = CAShapeLayer()
        border.name = "strikethrough"
        border.fillColor = nil
        border.opacity = 1.0
        border.lineWidth = thickness
        border.strokeColor = color.cgColor
        
        let linePath = UIBezierPath()
        linePath.move(to: CGPoint(x: 0, y: bounds.height))
        linePath.addLine(to: CGPoint(x: bounds.width, y: 0))
        border.path = linePath.cgPath
        return border
    }
    
    func getMaskLayer() -> CALayer {
        let mask = CALayer()
        mask.backgroundColor = UIColor.white.cgColor
        mask.opacity = 0.3
        mask.frame = bounds
        return mask
    }
    
    //--------------------------------------------------
    // MARK: - Accessibility
    //--------------------------------------------------

    public func updateAccessibility() {
        
        var message = ""
        
        if let labelText = label.text, label.hasText {
            message += labelText + ", "
        }
        
        if let subLabelText = subTextLabel.text, subTextLabel.hasText {
            message += subLabelText + ", "
        }
        
        accessibilityLabel = message
        accessibilityTraits = .button
        
        if isSelected {
            accessibilityTraits.insert(.selected)
        }
        
        if !isEnabled {
            accessibilityTraits.insert(.notEnabled)
        }
    }
}

