using UnityEngine;
using UnityEngine.Tilemaps;

public class BuilderManager : MonoBehaviour {
  public BuilderSettings Settings;
  private GameObjectPool GameObjPool;

  private GameObject PreviewObj;
  private bool BuildMode = false;
  private Vector2 SpriteSize;
  private CapsuleDirection2D CapsuleDir;
  private float GridSize = 0.5f;
  private Collider2D[] bufferSmall = new Collider2D[10];
  private Collider2D[] bufferLarge = new Collider2D[20];
  private ContactFilter2D ContactFilter;
  private Vector3 SnappedPos;
  private VfxHandlerBase VfxHandler;

  void Awake() {
    GameObjPool = new GameObjectPool(Settings.ObjToSpawn);
    PreviewObj = Instantiate(Settings.ObjAsPreview);
    PreviewObj.SetActive(false);

    var sr = PreviewObj.GetComponent<SpriteRenderer>();
    var s = sr.sprite;
    SpriteSize = s.rect.size / s.pixelsPerUnit;
    CapsuleDir = SpriteSize.x > SpriteSize.y
        ? CapsuleDirection2D.Horizontal
        : CapsuleDirection2D.Vertical;

    ContactFilter = new ContactFilter2D();
    //ContactFilter.useLayerMask = true;
    //ContactFilter.layerMask = LayerMask.GetMask("Structural", "Terrain");  // only check these layers
    ContactFilter.useTriggers = false;  // ignore triggers
    ContactFilter.useDepth = true;
    ContactFilter.SetDepth(-Mathf.Infinity, Mathf.Infinity);

    VfxHandler = new VfxHandlerBase(Settings.Vfx);
  }

  void Update() {
    if (!BuildMode) return;

    Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    mousePos.z = 0;
    SnappedPos = new Vector3(
        Mathf.Round(mousePos.x / GridSize) * GridSize,
        Mathf.Round(mousePos.y / GridSize) * GridSize,
        0f);
    PreviewObj.transform.position = SnappedPos;

    if (Input.GetMouseButtonDown(0)) PlaceObject();
  }


  public void SetBuildMode(bool on) {
    BuildMode = on;
    PreviewObj?.SetActive(on);
  }

  void PlaceObject() {
    if (InvalidPlacement()) return;


    VfxHandler.PlayAll(SnappedPos);
    var obj = GameObjPool.Get(SnappedPos, Quaternion.identity);
  }

  private bool InvalidPlacement() {
    //Collider2D[] hits = Physics2D.OverlapCapsuleAll(pos, SpriteSize * 0.8f, CapsuleDir, 0);
    //foreach (var hit in hits) 
    //  if (hit.CompareTag("Structural"))
    //    return false;


    //hits = Physics2D.OverlapCapsuleAll(pos, SpriteSize, CapsuleDir, 0);
    //foreach (var hit in hits) 
    //  if (hit.GetComponent<TilemapCollider2D>())
    //    return false;

    int count = Physics2D.OverlapCapsule(SnappedPos, SpriteSize * 0.8f, CapsuleDir, 0f, ContactFilter, bufferSmall);
    for (int i = 0; i < count; i++)
      if (bufferSmall[i].CompareTag("Structural"))
        return true;

    count = Physics2D.OverlapCapsule(SnappedPos, SpriteSize, CapsuleDir, 0f, ContactFilter, bufferLarge);
    for (int i = 0; i < count; i++)
      if (bufferLarge[i].GetComponent<TilemapCollider2D>())
        return true;


    Vector3 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    worldPos.z = 0f;

    GameObject groundGO = GameObject.FindGameObjectWithTag("Ground");
    if (!groundGO) return true;

    Tilemap tilemap = groundGO.GetComponent<Tilemap>();
    if (!tilemap) return true;

    Vector3Int cellPos = tilemap.WorldToCell(worldPos);
    TileBase tile = tilemap.GetTile(cellPos);
    if (!tile) return true;

    return false;
  }

  void OnDrawGizmos() {
    Vector2 center = SnappedPos;
    Vector2 size = SpriteSize;
    float radius = size.x / 2 * 0.8f;
    float height = size.y / 2 * 0.8f;

    if (SpriteSize.x != SpriteSize.y) {
      Vector2 top = center + Vector2.up * (height / 2 - radius);
      Vector2 bottom = center + Vector2.down * (height / 2 - radius);

      Gizmos.color = Color.green;
      Gizmos.DrawWireCube(center, new Vector2(size.x, height - 2 * radius));
      Gizmos.DrawWireSphere(top, radius);
      Gizmos.DrawWireSphere(bottom, radius);
    } else {
      Gizmos.color = Color.green;
      Gizmos.DrawWireSphere(center, radius);
    }
  }
}
