using System;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Grid {
    public class GridSystem<TGridObject> {
        private readonly float cellSize;
        private readonly TGridObject[,] gridObjectArray;

        public GridSystem(int width, int height, float cellSize, Func<GridSystem<TGridObject>, GridPosition, TGridObject> createGridObject) {
            Width = width;
            Height = height;
            this.cellSize = cellSize;

            gridObjectArray = new TGridObject[width, height];
            for (int x = 0; x < width; x++) {
                for (int z = 0; z < height; z++) {
                    gridObjectArray[x, z] = createGridObject(this, new(x, z));
                }
            }
        }

        public int Height { get; }
        public int Width { get; }

        public Vector3 GetWorldPosition(GridPosition gridPosition) => new Vector3(gridPosition.X, 0, gridPosition.Z) * cellSize;

        public GridPosition GetGridPosition(Vector3 worldPosition) => new(Mathf.RoundToInt(worldPosition.x / cellSize), Mathf.RoundToInt(worldPosition.z / cellSize));

        public void CreateDebugObjects(Transform debugPrefab) {
            for (int x = 0; x < Width; x++) {
                for (int z = 0; z < Height; z++) {
                    GridPosition gridPosition = new(x, z);
                    Transform debugTransform = Object.Instantiate(debugPrefab, GetWorldPosition(gridPosition), Quaternion.identity);
                    GridDebugObject gridDebugObject = debugTransform.GetComponent<GridDebugObject>();
                    gridDebugObject.SetGridObject(GetGridObject(gridPosition));
                }
            }
        }

        public TGridObject GetGridObject(GridPosition gridPosition) => gridObjectArray[gridPosition.X, gridPosition.Z];

        public bool IsValidGridPosition(GridPosition gridPosition) => gridPosition is { X: >= 0, Z: >= 0 } && gridPosition.X < Width && gridPosition.Z < Height;
    }
}