namespace Player
{
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class TruckBedVisuals : MonoBehaviour
    {
        [Header("Настройки кузова")]
        public Transform bedStartPoint; 
        public GameObject visualBoxPrefab; 
        
        [Header("Сетка укладки")]
        public int columns = 3; 
        public int rows = 3;    
        
        [Header("Размеры и отступы ")]
        public bool uniformScale = true;
        public Vector3 boxSize = new Vector3(1f, 1f, 1f);
        public Vector3 boxPadding = new Vector3(0.05f, 0.05f, 0.05f);

        [Header("Отрисовка в редакторе")]
        public int gizmoPreviewLayers = 3;

        [Header("Физика выпадения")]
        public float dropUpForce = 5f;
        public float dropBackForce = 15f;
        public float dropTorque = 10f;

        private Stack<GameObject> _stackedBoxes = new Stack<GameObject>();
        private Collider _carCollider;

        private void OnValidate()
        {
            if (uniformScale)
            {
                boxSize.y = boxSize.x;
                boxSize.z = boxSize.x;

                boxPadding.y = boxPadding.x;
                boxPadding.z = boxPadding.x;
            }
        }
        
        void Awake()
        {
            _carCollider = GetComponent<Collider>();
        }

        private void OnEnable()
        {
            GameEvents.OnBoxAddedToTruck += AddBox;
            GameEvents.OnBoxLostFromTruck += DropBox;
        }

        private void OnDisable()
        {
            GameEvents.OnBoxAddedToTruck -= AddBox;
            GameEvents.OnBoxLostFromTruck -= DropBox;
        }
        
        private void OnDrawGizmos()
        {
            if (bedStartPoint == null) return;
            
            Gizmos.color = new Color(0f, 1f, 0f, 0.5f); 
            
            Vector3 step = boxSize + boxPadding;

            // Сохраняем старую матрицу и применяем трансформацию якоря кузова.
            // Теперь сетка будет крутиться и двигаться вместе с машиной!
            Matrix4x4 oldMatrix = Gizmos.matrix;
            Gizmos.matrix = bedStartPoint.localToWorldMatrix;
            
            for (int layer = 0; layer < gizmoPreviewLayers; layer++)
            {
                for (int x = 0; x < columns; x++)
                {
                    for (int z = 0; z < rows; z++)
                    {
                        Vector3 boxCenter = new Vector3(x * step.x, layer * step.y, -z * step.z);
                        Gizmos.DrawWireCube(boxCenter, boxSize);
                    }
                }
            }
            
            Gizmos.matrix = oldMatrix;
        }

        private void AddBox()
        {
            if (visualBoxPrefab == null || bedStartPoint == null) return;

            int index = _stackedBoxes.Count;
            
            int layer = index / (columns * rows);
            int indexInLayer = index % (columns * rows);
            int x = indexInLayer % columns;
            int z = indexInLayer / columns;
            
            Vector3 step = boxSize + boxPadding;
            Vector3 localPos = new Vector3(x * step.x, layer * step.y, -z * step.z);
            
            GameObject newBox = SimpleObjectPool.Instance.Get(visualBoxPrefab, bedStartPoint.position, bedStartPoint.rotation);
            
            newBox.transform.SetParent(bedStartPoint);
            newBox.transform.localPosition = localPos;
            newBox.transform.localRotation = Quaternion.identity;
            newBox.transform.localScale = boxSize;

            Rigidbody rb = newBox.GetComponent<Rigidbody>();
            if (rb != null) rb.isKinematic = true;
            
            Collider coll = newBox.GetComponent<Collider>();
            if (coll != null) coll.enabled = false; 

            _stackedBoxes.Push(newBox);
        }

        private void DropBox()
        {
            if (_stackedBoxes.Count == 0) return;

            GameObject boxToDrop = _stackedBoxes.Pop();
            boxToDrop.transform.SetParent(null);
            
            Collider coll = boxToDrop.GetComponent<Collider>();
            if (coll != null) 
            {
                coll.enabled = true;
                if (_carCollider != null) Physics.IgnoreCollision(coll, _carCollider);
            }

            Rigidbody rb = boxToDrop.GetComponent<Rigidbody>();
            if (rb != null)
            {
                rb.isKinematic = false;
                
                Rigidbody carRb = GetComponent<Rigidbody>();
                if (carRb != null) rb.linearVelocity = carRb.linearVelocity;

                Vector3 force = transform.up * dropUpForce - transform.forward * dropBackForce;
                rb.AddForce(force, ForceMode.Impulse);
                rb.AddTorque(Random.insideUnitSphere * dropTorque, ForceMode.Impulse);
            }

            StartCoroutine(ReturnBoxToPool(boxToDrop, 3f));
        }

        IEnumerator ReturnBoxToPool(GameObject box, float delay)
        {
            yield return new WaitForSeconds(delay);
            SimpleObjectPool.Instance.ReturnToPool(visualBoxPrefab, box);
        }
    }
}