using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LevelGrid : MonoBehaviour
{
    [SerializeField] private Transform debugGridObjectPrefab;
    [SerializeField] private int width;
    [SerializeField] private int height;
    [SerializeField] private float cellSize;
    [SerializeField] private LayerMask obstaclesLayerMask;

    public static LevelGrid Instance {get; private set;}
    public event EventHandler OnAnyUnitMovedGridPosition;

    private GridSystem<GridObject> gridSystem;
  
    private void Awake() {

        if (Instance != null)
        {
            Debug.LogError("There's more than one LevelGrid" + transform + " - " + Instance);
            Destroy(gameObject);
            return;
        }
        Instance = this;        

        gridSystem = new GridSystem<GridObject>(width,height,cellSize, (GridSystem<GridObject> g, GridPosition gridPosition) => new GridObject(g,gridPosition));
        gridSystem.CreateDebugObjects(debugGridObjectPrefab);
    }

    private void Start() {
        Pathfinding.Instance.Setup(width,height,cellSize);
    }
    public void AddUnitAtGridPosition(GridPosition gridPosition, Unit unit) {
        if (gridSystem != null) {
            GridObject gridObject = gridSystem.GetGridObject(gridPosition);
            gridObject.AddUnit(unit);
        }
    }

    public Unit GetUnitAtGridPosition(GridPosition gridPosition) {
        Unit unitAtGridPosition = null;
        if (HasAnyUnitOnGridPosition(gridPosition)) {
            GridObject gridObject = gridSystem.GetGridObject(gridPosition);
            unitAtGridPosition = gridObject.GetUnit();
        }
        
        return unitAtGridPosition;
    }

    public void ClearUnitAtGridPosition(GridPosition gridPosition, Unit unit) {
        if (gridSystem != null) {
            GridObject gridObject = gridSystem.GetGridObject(gridPosition);
            gridObject.RemoveUnit(unit);            
        }
    }

    public bool IsLineOfSight(GridPosition sourcePosition, GridPosition DestinationPosition, float height) {
        Vector3 sourceWorldPosition = LevelGrid.Instance.GetWorldPosition(sourcePosition);
        Vector3 targetWorldPosition = LevelGrid.Instance.GetWorldPosition(DestinationPosition);

        Vector3 shotDirection = (targetWorldPosition - sourceWorldPosition).normalized;

        return  (!Physics.Raycast(
                    sourceWorldPosition + Vector3.up * height,
                    shotDirection,
                    Vector3.Distance(sourceWorldPosition, targetWorldPosition),
                    obstaclesLayerMask));
    }

    public void UnitMovedGridPosition(GridPosition gridPosition, GridPosition newGridPosition, Unit unit) {
        if (gridSystem != null) {
            ClearUnitAtGridPosition(gridPosition, unit);
            AddUnitAtGridPosition(newGridPosition, unit);
            OnAnyUnitMovedGridPosition?.Invoke(this, EventArgs.Empty);
        }
    }
    public GridPosition GetGridPosition(Vector3 worldPosition) => gridSystem.GetGridPosition(worldPosition);
    public bool IsValidGridPosition(GridPosition gridPosition) => gridSystem.IsValidGridPosition(gridPosition);
    public bool HasAnyUnitOnGridPosition(GridPosition gridPosition) => gridSystem.GetGridObject(gridPosition).HasAnyUnitOnGridPosition();
    public Vector3 GetWorldPosition(GridPosition gridPosition) => gridSystem.GetWorldPosition(gridPosition);
    public int GetWidth() => gridSystem.GetWidth();
    public int GetHeight() => gridSystem.GetHeight();

    public IInteractable GetInteractableAtGridPosition(GridPosition gridPosition) => gridSystem.GetGridObject(gridPosition).interactable;
    public IInteractable SetInteractableAtGridPosition(GridPosition gridPosition, IInteractable newInteractable) => gridSystem.GetGridObject(gridPosition).interactable = newInteractable;

}