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

public abstract class DraggablePlaceholder : MonoBehaviour
{
    [SerializeField]
    protected Color _validColor = Color.green;
    [SerializeField]
    protected Color _invalidColor = Color.red;
    public Transform Outline { get; set; }

    protected Camera _mainCamCache;
    protected Rect _lvlBoundsCache;
    protected bool _isOnValidPosition;
    
    /// <summary>
    /// calculate level boundaries and finds main camera.
    /// </summary>
    protected virtual void Start()
    {
        _mainCamCache = Camera.main;
        _lvlBoundsCache = LevelManager.Instance.CurrentLevel.CalculateBounds();
        _lvlBoundsCache.xMax += 1;
        _lvlBoundsCache.yMax += 1;
        UpdatePosition();
    }

    /// <summary>
    /// check for mouse click being released (and tries to place object)<br/>
    /// also updates placeholder's position and shows if position is valid
    /// </summary>
    protected virtual void Update()
    {
        if (!Input.GetMouseButton(0))
        {
            if (_isOnValidPosition)
            {
                Place();
            }
            Destroy(gameObject);
        }

        UpdatePosition();

        _isOnValidPosition = CanBePlacedHere();
        ShowValidity();
    }

    /// <summary>
    /// sets the position of the placeholder on the grid so it follows the mouse
    /// </summary>
    protected virtual void UpdatePosition()
    {
        var mousePos = Vector3Int.RoundToInt(_mainCamCache.ScreenToWorldPoint(Input.mousePosition));
        mousePos.z = 0;

        if (!_lvlBoundsCache.Contains(mousePos)) return;
        transform.position = mousePos;

    }

    /// <summary>
    /// helps determine if a unit can be placed on the tile sitting at unit's position (out of bound? obstacle? invalid tile?<br/>
    /// default behaviour is : you cant place anything over any already existing thing<br/>
    /// override to change this behaviour
    /// </summary>
    public virtual bool CanBePlacedHere()
    {
        return !LevelManager.Instance.Has<ILevelObject>(obj => obj.Position.IsContainedIn(transform.position));
    }

    /// <summary>
    /// how your character will appear depending on the validity of the tile you want to put them on<br/>
    /// default behaviour is changes color of all sprite renderers of the Outline Transform to red if invalid, green otherwise
    /// </summary>
    /// <param name="isValidPosition"></param>
    /// <returns></returns>
    public virtual void ShowValidity()
    {
        Color getColor() => _isOnValidPosition ? _validColor : _invalidColor;

        foreach (var child in Outline.GetComponentsInChildren<SpriteRenderer>(true))
        {
            child.color = getColor();
        }
    }
    public abstract void Place();
}
