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

public class PlayerInput : MonoBehaviour
{
    private enum Mode
    {
        UnitMode,
        BuildingMode,
    }

    [SerializeField] private Marker m_marker;

    private Unit m_selectedUnit;
    private Mode m_currentMode;

    private void Start()
    {
        m_currentMode = Mode.UnitMode;
    }

    private void Update()
    {
        if (!m_selectedUnit)
            m_selectedUnit = null;

        //if (Input.GetKeyDown(KeyCode.F1))
        //    ChangeMode(Mode.UnitMode);

        //if (Input.GetKeyDown(KeyCode.F2))
        //    ChangeMode(Mode.BuildingMode);

        if (Input.GetMouseButtonDown(0))
            LeftClick();

        if (Input.GetMouseButtonDown(1))
            RightClick();
    }

    private void ChangeMode(Mode newMode)
    {
        Debug.LogFormat("Changed interaction mode to {0}", newMode);
        m_selectedUnit?.Select();
        m_selectedUnit = null;
        m_currentMode = newMode;
    }

    private void LeftClick()
    {
        switch (m_currentMode)
        {
            case Mode.UnitMode:
                SelectUnit();
                break;
            case Mode.BuildingMode:
                ConstructBuilding();
                break;
            default:
                break;
        }
    }

    private void RightClick()
    {
        switch (m_currentMode)
        {
            case Mode.UnitMode:
                CommandUnit();
                break;
            case Mode.BuildingMode:
                DestroyBuilding();
                break;
            default:
                break;
        }
    }

    private void SelectUnit()
    {
        var go = GetObjectAtMouse(1 << 7);
        if (go && go.TryGetComponent<Unit>(out Unit unit))
        {
            //Deselect old selected character.
            m_selectedUnit?.Select();

            Debug.LogFormat("Selected Unit {0}", unit.name);
            m_selectedUnit = unit;
            m_selectedUnit.Select();
        }
        else
        {
            //Deselect old selected character.
            m_selectedUnit?.Select();
            m_selectedUnit = null;
        }
    }

    private void CommandUnit()
    {
        if (m_selectedUnit)
        {
            var tile = GetTileAtMouse();
            if (tile != null)
            {
                if (Input.GetKey(KeyCode.LeftShift) == false)
                {
                    m_selectedUnit.ClearCommandQueue();
                }

                var position = GetWorldPos();
                switch (tile.Type)
                {
                    case Tile.TileType.Ground:
                    case Tile.TileType.Building:
                        m_selectedUnit.Enqueue(new MoveCommand(tile));
                        break;
                    case Tile.TileType.Ladder:
                        m_selectedUnit.Enqueue(new MoveCommand(tile));
                        m_selectedUnit.Enqueue(new ClimbLadderCommand());
                        break;
                    case Tile.TileType.Wall:
                        if (MapManager.Distance(tile, MapManager.WorldPosToTile(m_selectedUnit.transform.position)) < MapManager.TileSize)
                        {
                            m_selectedUnit.Enqueue(new MineCommand(tile));
                        }
                        else
                        {
                            var path = MapManager.Instance.FindPath(MapManager.WorldPosToTile(m_selectedUnit.transform.position), tile);
                            if (path.Valid())
                            {
                                m_selectedUnit.Enqueue(new MoveCommand(path));
                                m_selectedUnit.Enqueue(new MineCommand(tile));
                            }
                        }
                        break;
                    default:
                        break;
                }

                //Marker
                m_marker.gameObject.SetActive(true);
                m_marker.WakeUp();
                m_marker.transform.position = position;
            }
        }
    }

    private void ConstructBuilding()
    {
        var tile = GetTileAtMouse();
        MapManager.Instance.ConstructBuilding<Stockpile>(tile);
    }

    private void DestroyBuilding()
    {
        var tile = GetTileAtMouse();
        tile?.Building?.Demolish();
    }

    private static GameObject GetObjectAtMouse(int layerMask = 0)
    {
        var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out RaycastHit hit, 5000f, (1 << 7)))
        {
            return hit.transform.gameObject;
        }
        else
        {
            return null;
        }
    }

    private static Vector3 GetWorldPos()
    {
        return MapManager.ScreenPosToWorld(Input.mousePosition);
    }

    private static Tile GetTileAtMouse()
    {
        return MapManager.Instance.GetTile(MapManager.WorldPosToTile(GetWorldPos()));
    }
}
