using UnityEngine;

namespace NBF
{
    [RequireComponent(typeof(LineRenderer))]
    public class RopeLineRenderer : MonoBehaviour, IRopeRenderer
    {
        [SerializeField] private bool useWorldSpace = true;
        [SerializeField] private bool syncWidthWithRenderRadius = true;
        [SerializeField] private float widthMultiplier = 2f;

        private VerletRope _rope;
        private LineRenderer _lineRenderer;
        private Vector3[] _positions;

        private void Awake()
        {
            _lineRenderer = GetComponent<LineRenderer>();
            ConfigureLineRenderer();
        }

        public void Bind(VerletRope rope)
        {
            _rope = rope;
        }

        public void Rebuild()
        {
            if (_rope == null) return;

            if (!_lineRenderer)
                _lineRenderer = GetComponent<LineRenderer>();

            ConfigureLineRenderer();
            ResizePositionBuffer(_rope.Nodes.Count);
            ApplyWidth();
            SyncPositions();
            _lineRenderer.enabled = true;
        }

        public void Render()
        {
            SyncPositions();
        }

        public void Clear()
        {
            if (!_lineRenderer)
                _lineRenderer = GetComponent<LineRenderer>();

            if (_lineRenderer)
            {
                _lineRenderer.positionCount = 0;
                _lineRenderer.enabled = false;
            }
        }

        private void ConfigureLineRenderer()
        {
            if (!_lineRenderer) return;

            _lineRenderer.useWorldSpace = useWorldSpace;
            _lineRenderer.loop = false;
        }

        private void ApplyWidth()
        {
            if (!_lineRenderer || _rope == null || !syncWidthWithRenderRadius) return;

            var width = Mathf.Max(0.0001f, _rope.RenderRadius * widthMultiplier);
            _lineRenderer.startWidth = width;
            _lineRenderer.endWidth = width;
        }

        private void ResizePositionBuffer(int nodeCount)
        {
            if (nodeCount < 0)
                nodeCount = 0;

            if (_positions == null || _positions.Length != nodeCount)
                _positions = new Vector3[nodeCount];

            _lineRenderer.positionCount = nodeCount;
        }

        private void SyncPositions()
        {
            if (_rope == null || !_lineRenderer) return;

            var nodes = _rope.Nodes;
            var nodeCount = nodes.Count;
            if (nodeCount == 0)
            {
                _lineRenderer.positionCount = 0;
                return;
            }

            ResizePositionBuffer(nodeCount);

            for (var i = 0; i < nodeCount; i++)
            {
                _positions[i] = useWorldSpace
                    ? nodes[i].position
                    : transform.InverseTransformPoint(nodes[i].position);
            }

            _lineRenderer.SetPositions(_positions);
        }
    }
}
