using AsteroidGame.Entities;
using AsteroidGame.ScriptableObjects;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Serialization;

namespace AsteroidGame.Handlers
{
    public class BuildingHandler : HandlerBase
    {
        [Header("Config")]
        [SerializeField] private Color _colorGhost = new Color(1f, 1f, 1f, 0.12f);
        [SerializeField] private Color _colorBuildingBlocked = new Color(1f, 0f, 0f, 0.12f);
        [SerializeField] private Material _ghostStructureMaterial;

        [Header("State")]
        [SerializeField] private bool _isBuilding;
        [SerializeField] private int _buildingSelector;

        [FormerlySerializedAs("_availableSStructures")]
        [FormerlySerializedAs("_availableStructures")]
        [Header("Structures")]
        [SerializeField] private SoStructureBaseList _availableSoStructures;

        #region Private

        private Color _colorCurrent;
        private Camera _camera;
        private Vector3 _tempVec;
        private Plane _buildPlane;
        private StructureBase _tempStructure;
        private StructureBase _ghostStructure;
        private MeshRenderer[] _ghostStructureMeshRenderers;

        #endregion

        protected override void OnEnable()
        {
            base.OnEnable();

            _camera = Camera.main;
            _buildPlane = new Plane(Vector3.up, Vector3.zero);
        }

        private void Update()
        {
            if (!_isBuilding) return;
            _ghostStructure.transform.position = GetPlanePoint();
            SetGhostColor(_ghostStructure.BuildPlacementBlocked ? _colorBuildingBlocked : _colorGhost);
        }

        private void SetGhostColor(Color newColor)
        {
            if (newColor == _colorCurrent) return;
            foreach (var meshRenderer in _ghostStructureMeshRenderers)
            {
                meshRenderer.material.color = newColor;
            }

            _colorCurrent = newColor;
        }

        protected override void OnLeftClick(InputAction.CallbackContext context)
        {
            PlaceStructure();
        }

        protected override void OnRightClick(InputAction.CallbackContext context)
        {
            AbortPlaceStructure();
        }

        protected override void OnBuild(InputAction.CallbackContext context)
        {
            EnterBuildMode(_buildingSelector);
        }

        private void PlaceStructure()
        {
            if (!_isBuilding) return;
            if (_ghostStructure.BuildPlacementBlocked) return;
            if (!Keyboard.current.shiftKey.isPressed)
            {
                DestroyGhostStructure();
                _isBuilding = false;
            }

            SpawnStructure();
        }

        private void AbortPlaceStructure()
        {
            if (!_isBuilding) return;
            DestroyGhostStructure();
            _isBuilding = false;
        }

        public void EnterBuildMode(int index)
        {
            if (_isBuilding) return;
            _isBuilding = true;
            SetBuildingIndex(index);
            SpawnGhostStructure();
        }

        private void SpawnGhostStructure()
        {
            _ghostStructure = Instantiate(_availableSoStructures._structureList[_buildingSelector], GetPlanePoint(),
                Quaternion.identity,
                transform);
            _ghostStructure.name = "GhostStructure";

            var rb = _ghostStructure.gameObject.AddComponent<Rigidbody>();
            rb.useGravity = false;

            _ghostStructureMeshRenderers = _ghostStructure.GetComponentsInChildren<MeshRenderer>();

            foreach (var meshRenderer in _ghostStructureMeshRenderers)
            {
                meshRenderer.material = _ghostStructureMaterial;
            }

            _ghostStructure.GetComponent<StructureBase>().enabled = false;
        }

        private void DestroyGhostStructure()
        {
            Destroy(_ghostStructure.gameObject);
        }

        private void SpawnStructure()
        {
            _tempStructure = Instantiate(_availableSoStructures._structureList[_buildingSelector], GetPlanePoint(),
                Quaternion.identity,
                transform);
        }

        #region Getters

        private Vector3 GetPlanePoint()
        {
            Ray ray = _camera.ScreenPointToRay(Mouse.current.position.ReadValue());
            if (_buildPlane.Raycast(ray, out float distance))
            {
                return ray.GetPoint(distance);
            }

            print("BuildPlaneNotHit");
            return Vector3.zero;
        }

        #endregion

        #region Setters

        public void SetBuildingIndex(int index)
        {
            _buildingSelector = index;
        }

        #endregion
    }
}