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

import Foundation

open class RadioSwatches: View {
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    public var collectionView: CollectionView!
    public var swatches: [RadioSwatchModel]?
    private var size: CGFloat?
    private var delegateObject: MVMCoreUIDelegateObject?
    
    //------------------------------------------------------
    // MARK: - Constraints
    //------------------------------------------------------
    public var collectionViewHeight: NSLayoutConstraint?
    private let cellSize: CGFloat = 54.0
    private let itemSpacing: CGFloat = 8.0
    
    //--------------------------------------------------
    // MARK: - Lifecycle
    //--------------------------------------------------
    open override func layoutSubviews() {
        super.layoutSubviews()
        // Accounts for any collection size changes
        setHeight()
        DispatchQueue.main.async {
            self.collectionView.collectionViewLayout.invalidateLayout()
        }
    }
    
    open override func setupView() {
        super.setupView()
        collectionView = createCollectionView()
        addSubview(collectionView)
        NSLayoutConstraint.constraintPinSubview(toSuperview: collectionView)
        collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 100)
        collectionViewHeight?.isActive = true
    }
    
    @objc override open func updateView(_ size: CGFloat) {
        super.updateView(size)
        self.size = size
        collectionView.updateView(size)
    }
    
    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? RadioSwatchesModel else { return }
        swatches = model.swatches
        FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
        collectionView.reloadData()
    }
    
    //------------------------------------------------------
    // MARK: - Methods
    //------------------------------------------------------
    /// Creates the collection view.
    open func createCollectionView() -> CollectionView {
        let collection = CollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())
        collection.dataSource = self
        collection.delegate = self
        collection.register(RadioSwatchCollectionViewCell.self, forCellWithReuseIdentifier: "RadioSwatchCollectionViewCell")
        return collection
    }
    
    /// Creates the layout for the collection.
    open func createCollectionViewLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.minimumLineSpacing = itemSpacing
        layout.minimumInteritemSpacing = itemSpacing
        return layout
    }
    
    open func setHeight() {
        guard let swatches = swatches, swatches.count > 0 else {
            collectionViewHeight?.constant = 0
            return
        }
        // Calculate the height
        let swatchesInRow = floor(CGFloat(collectionView.bounds.width/(cellSize + itemSpacing)))
        let numberOfRows = ceil(CGFloat(swatches.count)/swatchesInRow)
        let height = (numberOfRows * cellSize) + (itemSpacing * (numberOfRows-1))
        
        if let oldHeight = collectionViewHeight?.constant,
            height != oldHeight {
            // Notify delegate of height change, called async to avoid various race conditions caused while happening while laying out initially.
            DispatchQueue.main.async {
                self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self)
            }
        }
        collectionViewHeight?.constant = CGFloat(height)
    }
    
    open func updateAccessibilityValue(collectionView: UICollectionView, cell: RadioSwatchCollectionViewCell, 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: - Delegate methods
//------------------------------------------------------
extension RadioSwatches: UICollectionViewDelegateFlowLayout {
    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: cellSize, height: cellSize)
    }
}

extension RadioSwatches: UICollectionViewDataSource {
    open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return swatches?.count ?? 0
    }
    
    open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let molecule = swatches?[indexPath.row], let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RadioSwatchCollectionViewCell", for: indexPath) as? RadioSwatchCollectionViewCell else {
                fatalError()
        }
        cell.reset()
        cell.radioSwatch.isUserInteractionEnabled = false
        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 RadioSwatches: UICollectionViewDelegate {
    open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
        guard let molecule = swatches?[indexPath.row] else { return false }
        return molecule.enabled
    }
    
    open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return }
        cell.radioSwatch.selectSwatch()
        _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
        cell.updateAccessibility()
    }
    
    open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return }
        cell.radioSwatch.deselectSwatch()
        cell.updateAccessibility()
    }
}
