//
//  EntryFieldContainer.swift
//  MVMCoreUI
//
//  Created by Kevin Christiano on 11/12/19.
//  Copyright © 2019 Verizon Wireless. All rights reserved.
//

import UIKit


@objcMembers open class EntryFieldContainer: View {
    //--------------------------------------------------
    // MARK: - Drawing Properties
    //--------------------------------------------------
    
    /// The bottom border line. Height is dynamic based on scenario.
    public var bottomBar: CAShapeLayer? = {
        let layer = CAShapeLayer()
        layer.backgroundColor = UIColor.mvmBlack.cgColor
        layer.drawsAsynchronously = true
        layer.anchorPoint = CGPoint(x: 0.5, y: 1.0);
        return layer
    }()
    
    /// Total control over the drawn top, bottom, left and right borders.
    public var disableAllBorders = false {
        didSet { bottomBar?.isHidden = disableAllBorders }
    }
    
    private(set) var fieldState: FieldState = .original {
        didSet (oldState) {
            // Will not update if new state is the same as old.
            if fieldState != oldState {
                DispatchQueue.main.async { [weak self] in
                    guard let self = self else { return }
                    
                    self.fieldState.setStateUI(for: self)
                }
            }
        }
    }
    
    /// Determines if the top, left, and right borders should be drawn.
    private var hideBorders = false
    
    public var borderStrokeColor: UIColor = .mvmCoolGray3
    private var borderPath: UIBezierPath = UIBezierPath()
    
    //--------------------------------------------------
    // MARK: - Property Observers
    //--------------------------------------------------
    
    private var _isEnabled: Bool = true
    private var _showError: Bool = false
    private var _isLocked: Bool = false
    private var _isSelected: Bool = false
    
    public var isEnabled: Bool {
        get { return _isEnabled }
        set (enabled) {
            
            _isEnabled = enabled
            _isLocked = false
            _isSelected = false
            _showError = false
            
            fieldState = enabled ? .original : .disabled
        }
    }
    
    public var showError: Bool {
        get { return _showError }
        set (error) {
            
            _showError = error
            _isEnabled = true
            _isLocked = false
            _isSelected = false
            
            fieldState = error ? .error : .original
        }
    }
    
    public var isLocked: Bool {
        get { return _isLocked }
        set (locked) {
            
            _isLocked = locked
            _isEnabled = true
            _isSelected = false
            _showError = false
            
            fieldState = locked ? .locked : .original
        }
    }
    
    public var isSelected: Bool {
        get { return _isSelected }
        set (selected) {
            
            _isSelected = selected
            _isLocked = false
            _isEnabled = true
            
            if _showError {
                fieldState = selected ? .selectedError : .error
            } else {
                fieldState = selected ? .selected : .original
            }
        }
    }
    
    //--------------------------------------------------
    // MARK: - Delegate
    //--------------------------------------------------
    
    /// Holds reference to delegateObject to inform molecular tableView of an update.
    var delegateObject: MVMCoreUIDelegateObject?
    
    //--------------------------------------------------
    // MARK: - Lifecycle
    //--------------------------------------------------
    
    open override func layoutSubviews() {
        super.layoutSubviews()
        
        refreshUI(bottomBarSize: showError ? 4 : 1)
    }
    
    open override func updateView(_ size: CGFloat) {
        super.updateView(size)
        
        refreshUI()
    }
    
    /// This handles the top, left, and right border lines.
    open override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        borderPath.removeAllPoints()
        
        if !disableAllBorders && !hideBorders {
            // Brings the other half of the line inside the view to prevent cropping.
            let origin = bounds.origin
            let size = frame.size
            let insetLean: CGFloat = 0.5
            borderPath.lineWidth = 1
            
            borderPath.move(to: CGPoint(x: origin.x + insetLean, y: origin.y + size.height))
            borderPath.addLine(to: CGPoint(x: origin.x + insetLean, y: origin.y + insetLean))
            borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + insetLean))
            borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + size.height))
            
            borderStrokeColor.setStroke()
            borderPath.stroke()
        }
    }
    
    override open func setupView() {
        super.setupView()
        
        isAccessibilityElement = false
        isOpaque = false
        
        if let bottomBar = bottomBar {
            layer.addSublayer(bottomBar)
        }
    }
    
    //--------------------------------------------------
    // MARK: - Draw States
    //--------------------------------------------------
    
    public enum FieldState {
        case original
        case error
        case selectedError
        case selected
        case locked
        case disabled
        
        public func setStateUI(for formField: EntryFieldContainer) {
            
            switch self {
            case .original:
                formField.originalUI()
                
            case .error:
                formField.errorUI()
                
            case .selectedError:
                formField.selectedErrorUI()
                
            case .selected:
                formField.selectedUI()
                
            case .locked:
                formField.lockedUI()
                
            case .disabled:
                formField.disabledUI()
            }
        }
    }
    
    open func originalUI() {
        
        isUserInteractionEnabled = true
        hideBorders = false
        borderStrokeColor = .mvmCoolGray3
        bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor
        refreshUI(bottomBarSize: 1)
    }
    
    open func errorUI() {
        
        isUserInteractionEnabled = true
        hideBorders = false
        borderStrokeColor = .mvmOrange
        bottomBar?.backgroundColor = UIColor.mvmOrange.cgColor
        refreshUI(bottomBarSize: 4)
    }
    
    open func selectedErrorUI() {
        
        isUserInteractionEnabled = true
        hideBorders = false
        borderStrokeColor = .mvmBlack
        bottomBar?.backgroundColor = UIColor.mvmOrange.cgColor
        refreshUI(bottomBarSize: 4)
    }
    
    open func selectedUI() {
        
        isUserInteractionEnabled = true
        hideBorders = false
        borderStrokeColor = .mvmBlack
        bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor
        refreshUI(bottomBarSize: 1)
    }
    
    open func lockedUI() {
        
        isUserInteractionEnabled = false
        hideBorders = true
        borderStrokeColor = .clear
        bottomBar?.backgroundColor = UIColor.clear.cgColor
        refreshUI(bottomBarSize: 1)
    }
    
    open func disabledUI() {
        
        isUserInteractionEnabled = false
        hideBorders = false
        borderStrokeColor = .mvmCoolGray3
        bottomBar?.backgroundColor = UIColor.mvmCoolGray3.cgColor
        refreshUI(bottomBarSize: 1)
    }
    
    open func refreshUI(bottomBarSize: CGFloat? = nil, updateMoleculeLayout: Bool = false) {
        
        if !disableAllBorders {
            let size: CGFloat = bottomBarSize ?? (showError ? 4 : 1)
            var heightChanged = false
            
            if let bottomHeight = bottomBar?.bounds.height {
                heightChanged = size != bottomHeight
            }
            bottomBar?.frame = CGRect(x: 0, y: bounds.height - size, width: bounds.width, height: size)
            
            if updateMoleculeLayout || heightChanged {
                delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self)
            }
            
            setNeedsDisplay()
            layoutIfNeeded()
        }
    }
    
    //--------------------------------------------------
    // MARK: - MoleculeViewProtocol
    //--------------------------------------------------
    
    open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.set(with: model, delegateObject, additionalData)
        self.delegateObject = delegateObject
    }
}
