// Assets/_Project/Scripts/Combat/TeslaArcVisual.cs
using System.Collections.Generic;
using UnityEngine;

namespace TD.Combat
{
    /// <summary>
    /// Local-only electrical-arc visual for <see cref="TD.Core.TargetType.AllInRange"/>
    /// towers (Tesla Coil). Subscribes to <see cref="TowerCombat.OnAreaFired"/> and draws a
    /// jagged line from the tower's emitter point to every enemy hit, flashed for a moment.
    /// </summary>
    /// <remarks>
    /// Pure visualization — runs on every peer from the replicated fire broadcast; nothing
    /// here is networked. Arcs are pooled <see cref="LineRenderer"/>s reused across ticks.
    /// </remarks>
    [RequireComponent(typeof(TowerCombat))]
    public class TeslaArcVisual : MonoBehaviour
    {
        [Tooltip("Point the arcs originate from — the central top of the coil. " +
                 "If unset, falls back to one unit above the tower root.")]
        [SerializeField] private Transform emitter;

        [Tooltip("Material for the arc lines. Assign an unlit/additive material for a glow. " +
                 "If unset, a fallback Sprites/Default material is created at runtime.")]
        [SerializeField] private Material arcMaterial;

        [SerializeField] private Color arcColor = new Color(0.6f, 0.85f, 1f, 1f);
        [SerializeField] private float arcWidth = 0.06f;
        [Tooltip("How long each arc flash stays visible, in seconds.")]
        [SerializeField] private float arcDuration = 0.12f;
        [Tooltip("Number of points per arc. More = more jagged detail.")]
        [SerializeField] private int segmentsPerArc = 6;
        [Tooltip("Random offset applied to interior arc points for the lightning look.")]
        [SerializeField] private float jitter = 0.2f;

        private TowerCombat combat;
        private readonly List<LineRenderer> pool = new List<LineRenderer>();
        private float hideAt = -1f;

        private void Awake() => combat = GetComponent<TowerCombat>();

        private void OnEnable()
        {
            if (combat != null) combat.OnAreaFired += HandleAreaFired;
        }

        private void OnDisable()
        {
            if (combat != null) combat.OnAreaFired -= HandleAreaFired;
        }

        private void Update()
        {
            if (hideAt >= 0f && Time.time >= hideAt)
            {
                for (int i = 0; i < pool.Count; i++) pool[i].enabled = false;
                hideAt = -1f;
            }
        }

        private void HandleAreaFired(Vector3[] positions)
        {
            if (positions == null) return;

            Vector3 origin = emitter != null ? emitter.position : transform.position + Vector3.up;

            for (int i = 0; i < positions.Length; i++)
            {
                var lr = GetLine(i);
                DrawArc(lr, origin, positions[i]);
                lr.enabled = true;
            }

            // Disable any leftover lines from a previous, larger tick.
            for (int i = positions.Length; i < pool.Count; i++)
                pool[i].enabled = false;

            hideAt = Time.time + arcDuration;
        }

        private LineRenderer GetLine(int index)
        {
            while (pool.Count <= index)
            {
                var go = new GameObject($"Arc_{pool.Count}");
                go.transform.SetParent(transform, worldPositionStays: false);
                var lr = go.AddComponent<LineRenderer>();
                lr.useWorldSpace   = true;
                lr.widthMultiplier = arcWidth;
                lr.numCapVertices  = 2;
                lr.textureMode     = LineTextureMode.Stretch;
                lr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
                lr.material   = arcMaterial != null
                    ? arcMaterial
                    : new Material(Shader.Find("Sprites/Default"));
                lr.startColor = lr.endColor = arcColor;
                lr.enabled    = false;
                pool.Add(lr);
            }
            return pool[index];
        }

        private void DrawArc(LineRenderer lr, Vector3 a, Vector3 b)
        {
            int n = Mathf.Max(2, segmentsPerArc);
            lr.positionCount = n;
            for (int s = 0; s < n; s++)
            {
                float t = s / (float)(n - 1);
                Vector3 p = Vector3.Lerp(a, b, t);
                // Jitter interior points only — endpoints stay anchored to the coil and enemy.
                if (s != 0 && s != n - 1)
                    p += Random.insideUnitSphere * jitter;
                lr.SetPosition(s, p);
            }
        }
    }
}
