using Sirenix.OdinInspector;
using UnityEngine;

namespace VOID.Generic.Projectile.Drawers
{
    public class BeamProjectileDrawer : MonoBehaviour
    {
        [Title("Positions")]
        [SerializeField] private bool autoPositions;
        [HideIf(nameof(autoPositions))] [SerializeField] [Required] private Transform from;
        [HideIf(nameof(autoPositions))] [SerializeField] [Required] private Transform to;
        
        [Title("Prefabs")]
        [InfoBox("Those prefabs are from addon MagicArsenal located in <b>Assets/_ADDONS/MagicArsenal/Effects/Prefabs/Beams/Setup</b>")]
        [SerializeField] [Required] private GameObject beamLineRendererPrefab;
        [SerializeField] [Required] private GameObject beamStartPrefab;
        [SerializeField] [Required] private GameObject beamEndPrefab;

        [Title("Beam Options")] 
        [SerializeField] private float textureScrollSpeed = 5f;
        [SerializeField] private float textureLengthScale = 5f;

        [Title("Width Pulse Options")] 
        [SerializeField] private float startScale = 1.0f;
        [SerializeField] private float endScale = 1.0f;
        [SerializeField] private float pulseSpeed = 1.0f;

        private GameObject _beamStart;
        private GameObject _beamEnd;
        private GameObject _beam;
        private LineRenderer _line;
        
        private float _lerpValue;
        private bool _pulseExpanding;

        public void Awake()
        {
            if (autoPositions)
            {
                GetComponent<ProjectileObject>().onStart.AddListener(SetPositions);
            }
        }
        
        private void Start()
        {
            SpawnBeam();
        }

        private void SetPositions(ProjectileObject projectile)
        {
            from = projectile.caster.unitData.castPosition;
            to = projectile.gameObject.transform;
        }

        private void FixedUpdate()
        {
            if (_beam)
            {
                var fromPosition = from.position;
                var toPosition = to.position;
                
                _line.SetPosition(0, fromPosition);
                _line.SetPosition(1, toPosition);
                
                _beamStart.transform.position = fromPosition;
                _beamStart.transform.LookAt(toPosition);
                _beamEnd.transform.position = toPosition;
                _beamEnd.transform.LookAt(fromPosition);
                
                var distance = Vector3.Distance(fromPosition, toPosition);
                
                //This sets the scale of the texture so it doesn't look stretched
                _line.material.mainTextureScale = new Vector2(distance / textureLengthScale, 1);
                //This scrolls the texture along the beam if not set to 0
                _line.material.mainTextureOffset -= new Vector2(Time.deltaTime * textureScrollSpeed, 0);
            }

            _lerpValue += (_pulseExpanding ? 1 : -1) * Time.deltaTime * pulseSpeed;

            if (_lerpValue >= 1.0f)
            {
                _pulseExpanding = false;
                _lerpValue = 1.0f;
            }
            else if (_lerpValue <= 0.0f)
            {
                _pulseExpanding = true;
                _lerpValue = 0.0f;
            }

            var currentWidth = Mathf.Lerp(startScale, endScale, Mathf.Sin(_lerpValue * Mathf.PI));

            _line.startWidth = currentWidth;
            _line.endWidth = currentWidth;
        }

        private void SpawnBeam()
        {
            if (!beamLineRendererPrefab) return;
            
            _beam = Instantiate(beamLineRendererPrefab);
            _beam.transform.position = transform.position;
            _beam.transform.parent = transform;
            _beam.transform.rotation = transform.rotation;

            _line = _beam.GetComponent<LineRenderer>();
            _line.useWorldSpace = true;
            _line.positionCount = 2;

            _beamStart = beamStartPrefab ? Instantiate(beamStartPrefab, _beam.transform) : null;
            _beamEnd = beamEndPrefab ? Instantiate(beamEndPrefab, _beam.transform) : null;
        }
    }
}