//
//  RadioSwatch.swift
//  MVMCoreUI
//
//  Created by Lekshmi S on 01/04/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import UIKit


open class RadioSwatch: Control, MFButtonProtocol {
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    public let bottomText = Label(fontStyle: .RegularMicro)
    
    private var circleLayer: CAShapeLayer?
    private var selectedLayer: CALayer?
    private var strikeLayer: CALayer?
    private var maskLayer: CALayer?
    
    private var delegateObject: MVMCoreUIDelegateObject?
    var additionalData: [AnyHashable: Any]?

    public var radioSwatchModel: RadioSwatchModel? {
        return model as? RadioSwatchModel
    }
    
    public override var isSelected: Bool {
        didSet {
            updateAccessibility()
        }
    }
    
    public override var isEnabled: Bool {
        didSet {
            updateAccessibility()
        }
    }

    //--------------------------------------------------
    // MARK: - Lifecycle
    //--------------------------------------------------
    open override func updateView(_ size: CGFloat) {
        super.updateView(size)
        bottomText.updateView(size)
        layer.setNeedsDisplay()
    }
    
    open override func setupView() {
        super.setupView()

        addSubview(bottomText)
        bottomText.textAlignment = .center
        NSLayoutConstraint.constraintPinSubview(bottomText, pinTop: true, topConstant: 38, pinBottom: true, bottomConstant: 0, pinLeft: true, leftConstant: 0, pinRight: true, rightConstant: 0)
        addTarget(self, action: #selector(selectSwatch), for: .touchUpInside)
    }
    
    open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.set(with: model, delegateObject, additionalData)
        guard let model = model as? RadioSwatchModel else { return }
        self.delegateObject = delegateObject
        self.additionalData = additionalData
        bottomText.text = model.text
        isSelected = model.selected
        isEnabled = model.enabled && !model.readOnly
    }
    
    public override func reset() {
        super.reset()
        bottomText.text = nil
        isSelected = false
        isEnabled = true
    }
    
    //------------------------------------------------------
    // MARK: - State Handling
    //------------------------------------------------------
    
    open override func draw(_ layer: CALayer, in ctx: CGContext) {
        //Draw the swatch
        circleLayer?.removeFromSuperlayer()
        let circle = getCircle(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1)
        layer.addSublayer(circle)
        circleLayer = circle
        
        //Draw the strikethrough
        strikeLayer?.removeFromSuperlayer()
        if radioSwatchModel?.strikethrough ?? false {
            let line = getStrikeThrough(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1)
            layer.addSublayer(line)
            strikeLayer = line
        }
        
        //Draw the selected layer
        selectedLayer?.removeFromSuperlayer()
        if isSelected {
            let outerCircle = getSelectedLayer(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1)
            layer.addSublayer(outerCircle)
            selectedLayer = outerCircle
            bottomText.isHidden = false
        } else {
            bottomText.isHidden = true
        }
        
        //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 selectSwatch() {
        guard isEnabled, !isSelected else { return }
        isSelected = true
        radioSwatchModel?.selected = isSelected
        if let radioSwatchModel = radioSwatchModel, let actionModel = radioSwatchModel.action {
            Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioSwatchModel)
        }
        layer.setNeedsDisplay()
    }
    
    @objc open func deselectSwatch() {
        isSelected = false
        radioSwatchModel?.selected = isSelected
        layer.setNeedsDisplay()
    }
    
    func getCircle(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
        let circle = CAShapeLayer()
        circle.name = "innercircle"
        circle.fillColor = radioSwatchModel?.color.cgColor ?? UIColor.blue.cgColor
        circle.opacity = 1.0
        circle.lineWidth = thickness
        circle.strokeColor = color.cgColor
        
        let circlePath = UIBezierPath(ovalIn: CGRect(x: 12, y: 1, width: 30, height: 30))
        circle.path = circlePath.cgPath
        return circle
    }
    
    func getStrikeThrough(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
        let strikeThrough = CAShapeLayer()
        strikeThrough.name = "strikethrough"
        strikeThrough.fillColor = nil
        strikeThrough.opacity = 1.0
        strikeThrough.lineWidth = thickness
        strikeThrough.strokeColor = color.cgColor
        
        let linePath = UIBezierPath()
        linePath.move(to: CGPoint(x: 12, y: 31))
        linePath.addLine(to: CGPoint(x: 42, y: 1))
        strikeThrough.path = linePath.cgPath
        return strikeThrough
    }
    
    func getSelectedLayer(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
        circleLayer?.path = UIBezierPath(ovalIn: CGRect(x: 15, y: 4, width: 24, height: 24)).cgPath
        let circle = CAShapeLayer()
        circle.name = "outercircle"
        circle.fillColor = UIColor.clear.cgColor
        circle.opacity = 1.0
        circle.lineWidth = thickness
        circle.strokeColor = color.cgColor
        
        let circlePath = UIBezierPath(ovalIn: CGRect(x: 12, y: 1, width: 30, height: 30))
        circle.path = circlePath.cgPath
        return circle
    }
    
    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() {
        accessibilityLabel = bottomText.accessibilityLabel ?? bottomText.text
        
        accessibilityTraits = .button
        if isSelected {
            accessibilityTraits.insert(.selected)
        }
        if !isEnabled {
            accessibilityTraits.insert(.notEnabled)
        }
    }
}
