//
//  RadioBoxes.swift
//  MVMCoreUI
//
//  Created by Dhamodaram Nandi on 31/03/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import Foundation

public protocol RadioBoxSelectionDelegate: class {
    func selected(radioBox: RadioBoxModel)
}

open class RadioBoxes: View {
    
    public var collectionView: CollectionView!
    public var collectionViewHeight: NSLayoutConstraint!
    private let boxWidth: CGFloat = 151.0
    private let boxHeight: CGFloat = 64.0
    private var itemSpacing: CGFloat = 12.0
    private var numberOfColumns: CGFloat = 2.0
    private var radioBoxesModel: RadioBoxesModel? {
        return model as? RadioBoxesModel
    }
    public weak var radioDelegate: RadioBoxSelectionDelegate?
    private var delegateObject: MVMCoreUIDelegateObject?
    
    /// The models for the molecules.
    public var boxes: [RadioBoxModel]?
    
    private var size: CGFloat?
    
    open override func layoutSubviews() {
        super.layoutSubviews()
        // Accounts for any collection size changes
        DispatchQueue.main.async {
            self.collectionView.collectionViewLayout.invalidateLayout()
        }
    }
    
    open func updateAccessibilityValue(collectionView: UICollectionView, cell: RadioBoxCollectionViewCell, indexPath: IndexPath) {
        guard let format = MVMCoreUIUtility.hardcodedString(withKey: "index_string_of_total"),
              let indexString = MVMCoreUIUtility.getOrdinalString(forIndex: NSNumber(value: indexPath.row + 1)) else { return }
        let total = self.collectionView(collectionView, numberOfItemsInSection: indexPath.section)
        cell.accessibilityValue = String(format: format, indexString, total)
    }
    
    // MARK: - MVMCoreViewProtocol
    open override func setupView() {
        super.setupView()
        collectionView = createCollectionView()
        addSubview(collectionView)
        NSLayoutConstraint.constraintPinSubview(toSuperview: collectionView)
        collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 300)
        collectionViewHeight?.isActive = true
    }
    
    // MARK: - MoleculeViewProtocol
    open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.set(with: model, delegateObject, additionalData)
        self.delegateObject = delegateObject
        
        guard let model = model as? RadioBoxesModel else { return }
        boxes = model.boxes
        FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
        
        backgroundColor = model.backgroundColor?.uiColor
        
        registerCells()
        setHeight()
        collectionView.reloadData()
    }
    
    @objc override open func updateView(_ size: CGFloat) {
        super.updateView(size)
        self.size = size
        itemSpacing = Padding.Component.gutterFor(size: size)
        collectionView.updateView(size)
    }
    
    // MARK: - Creation
    
    /// Creates the layout for the collection.
    open func createCollectionViewLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.minimumLineSpacing = itemSpacing
        layout.minimumInteritemSpacing = itemSpacing
        return layout
    }
    
    /// Creates the collection view.
    open func createCollectionView() -> CollectionView {
        let collection = CollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())
        collection.dataSource = self
        collection.delegate = self
        return collection
    }
    
    /// Registers the cells with the collection view
    open func registerCells() {
        collectionView.register(RadioBoxCollectionViewCell.self, forCellWithReuseIdentifier: "RadioBoxCollectionViewCell")
    }
    
    // MARK: - JSON Setters
    open func setHeight() {
        guard let boxes = boxes, boxes.count > 0 else {
            collectionViewHeight.constant = 0
            return
        }
        
        // Calculate the height
        let rows = ceil(CGFloat(boxes.count) / numberOfColumns)
        let height = (rows * boxHeight) + ((rows - 1) * itemSpacing)
        collectionViewHeight?.constant = height
    }
}

extension RadioBoxes: UICollectionViewDelegateFlowLayout {
    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let itemWidth: CGFloat = (collectionView.bounds.width - itemSpacing) / numberOfColumns
        return CGSize(width: itemWidth, height: boxHeight)
    }
}

extension RadioBoxes: UICollectionViewDataSource {
    open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return boxes?.count ?? 0
    }
    
    open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let molecule = boxes?[indexPath.row],
              let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RadioBoxCollectionViewCell", for: indexPath) as? RadioBoxCollectionViewCell else {
            fatalError()
        }
        cell.reset()
        cell.radioBox.isUserInteractionEnabled = false
        
        if let color = radioBoxesModel?.boxesColor {
            cell.radioBox.backgroundColor = color.uiColor
        }
        if let color = radioBoxesModel?.selectedAccentColor {
            cell.radioBox.accentColor = color.uiColor
        }
        
        cell.set(with: molecule, delegateObject, nil)
        cell.updateView(size ?? collectionView.bounds.width)
        if molecule.selected {
            collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically)
        }
        updateAccessibilityValue(collectionView: collectionView, cell: cell, indexPath: indexPath)
        cell.layoutIfNeeded()
        return cell
    }
}

extension RadioBoxes: UICollectionViewDelegate {
    open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
        guard let molecule = boxes?[indexPath.row] else { return false }
        return molecule.enabled
    }
    
    open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
        cell.radioBox.selectBox()
        _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
        cell.updateAccessibility()
        guard let radioBox = boxes?[indexPath.row] else { return }
        radioDelegate?.selected(radioBox: radioBox)
    }
    
    open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
        cell.radioBox.deselectBox()
        cell.updateAccessibility()
    }
}
