//
//  AspectVGrid.swift
//  MemberWise
//
//  Created by Cédric Bahirwe on 08/09/2021.
//

import SwiftUI

struct AspectVGrid<Item, ItemView>: View
where Item: Identifiable, ItemView: View {
    internal init(items: [Item],
                  aspectRatio: CGFloat,
                  @ViewBuilder content: @escaping (Item) -> ItemView) {
        self.items = items
        self.aspectRatio = aspectRatio
        self.content = content
    }
    
    var items: [Item]
    var aspectRatio: CGFloat
    var content: (Item) -> ItemView
    
    var body: some View {
        GeometryReader { geometry in
            VStack {
                let width: CGFloat = widthThatFits(itemCount: items.count,
                                                   in: geometry.size,
                                                   itemAspectRatio: aspectRatio)
                
                LazyVGrid(columns: [adaptiveGridItem(for: width)], spacing: 0) {
                    ForEach(items) { item in
                        content(item)
                            .aspectRatio(aspectRatio,contentMode: .fit)
                    }
                }
                
                Spacer(minLength: 0)
            }
        }
    }
    
    
    /// Removes the default spacing of a `GridItem`
    /// - Parameter width: the minimum width of the `GridItem` to be returned
    /// - Returns: a `GridItem` without spacing
    private func adaptiveGridItem(for width: CGFloat) -> GridItem {
        var gridItem =  GridItem(.adaptive(minimum: width))
        gridItem.spacing = 0
        return gridItem
    }
    
    /// Calculates the accurate width for a `GridItem`
    /// - Parameters:
    ///   - itemCount: the number of elements to take into account
    ///   - size: the available space to take into account
    ///   - itemAspectRatio: the `GridItem` aspectRatio
    /// - Returns: returns the width of a `GridItem` based on its aspectRatio
    private func widthThatFits(itemCount: Int,
                               in size: CGSize,
                               itemAspectRatio: CGFloat) -> CGFloat {
        var columnCount = 1
        var rowCount = itemCount
        
        repeat {
            let itemWidth = size.width / CGFloat(columnCount)
            
            let itemheight = itemWidth / itemAspectRatio
            
            if CGFloat(rowCount) * itemheight < size.height {
                break
            }
            
            columnCount += 1
            rowCount = (itemCount + (columnCount - 1)) / columnCount 
            
            
        } while columnCount < itemCount
        
        if columnCount > itemCount {
            columnCount  = itemCount
        }
        
        
        return floor(size.width / CGFloat(columnCount))
        
    }
}
