//
//  BoardView.swift
//  TTTKit
//
//  Created by Shadowfacts on 12/21/22.
//

import SwiftUI

@available(iOS 16.0, *)
struct BoardView<Cell: View>: View {
    let board: any Board
    @Binding var cellSize: CGFloat
    let spacing: CGFloat
    let cellProvider: (_ column: Int, _ row: Int) -> Cell
    
    init(board: any Board, cellSize: Binding<CGFloat>, spacing: CGFloat, @ViewBuilder cellProvider: @escaping (Int, Int) -> Cell) {
        self.board = board
        self._cellSize = cellSize
        self.spacing = spacing
        self.cellProvider = cellProvider
    }
    
    var body: some View {
        ZStack {
            if let win = board.win {
                winOverlay(win)
            }
            
            Grid(horizontalSpacing: 10, verticalSpacing: 10) {
                GridRow {
                    cellProvider(0, 0)
                        .background(GeometryReader { proxy in
                            Color.clear
                                .preference(key: MarkSizePrefKey.self, value: proxy.size.width)
                                .onPreferenceChange(MarkSizePrefKey.self) { newValue in
                                    cellSize = newValue
                                }
                        })
                    cellProvider(1, 0)
                    cellProvider(2, 0)
                }
                GridRow {
                    cellProvider(0, 1)
                    cellProvider(1, 1)
                    cellProvider(2, 1)
                }
                GridRow {
                    cellProvider(0, 2)
                    cellProvider(1, 2)
                    cellProvider(2, 2)
                }
            }
            
            let sepOffset = (cellSize + spacing) / 2
            Separator(axis: .vertical)
                .offset(x: -sepOffset)
            Separator(axis: .vertical)
                .offset(x: sepOffset)
            Separator(axis: .horizontal)
                .offset(y: -sepOffset)
            Separator(axis: .horizontal)
                .offset(y: sepOffset)
        }
        .padding(.all, spacing / 2)
        .aspectRatio(1, contentMode: .fit)
    }
    
    private func winOverlay(_ win: Win) -> some View {
        let pointsWithIndices = win.points.map { ($0, $0.row * 3 + $0.column) }
        let cellSize = cellSize + spacing
        return ForEach(pointsWithIndices, id: \.1) { (point, _) in
            Rectangle()
                .foregroundColor(Color(UIColor.green))
                .opacity(0.5)
                .frame(width: cellSize, height: cellSize)
                .offset(x: CGFloat(point.column - 1) * cellSize, y: CGFloat(point.row - 1) * cellSize)
        }
    }
}

private struct MarkSizePrefKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}
