// Assets/_Project/Scripts/Gameplay/BuildRangeIndicator.cs
using UnityEngine;
using UnityEngine.Rendering.Universal;

namespace TD.Gameplay
{
    /// <summary>
    /// Visualizes a builder's build range as a decal projector circle on the ground.
    /// Visible only to the owning client, and only while placement mode is active.
    /// </summary>
    /// <remarks>
    /// <para>Sits as a child of the <see cref="Builder"/> GameObject. The
    /// <see cref="DecalProjector"/> renders a circular texture onto whatever ground
    /// geometry is below — flat plane or sloped terrain alike, no special handling needed.</para>
    ///
    /// <para><b>Owner-only.</b> Non-owning clients should not see other players' build
    /// range indicators (would be visual clutter). The decal projector is force-disabled
    /// for non-owners on spawn.</para>
    ///
    /// <para><b>Toggling.</b> The indicator is only visible when the local player is in
    /// placement mode. It checks <c>TowerPlacementController.IsPlacing</c> each frame
    /// and toggles the projector accordingly. When sized correctly the projector size
    /// matches <c>buildRange * 2</c> (diameter).</para>
    /// </remarks>
    public class BuildRangeIndicator : MonoBehaviour
    {
        [Tooltip("DecalProjector child component to drive. Auto-found in Awake if empty.")]
        [SerializeField] private DecalProjector projector;

        [Tooltip("Vertical thickness of the decal projector's projection volume. Should " +
                 "exceed your map's vertical range so the decal projects onto terrain at any height.")]
        [SerializeField] private float projectionDepth = 50f;

        // Cached references resolved lazily.
        private Builder cachedBuilder;
        private TowerPlacementController cachedPlacementController;

        // ----- Lifecycle --------------------------------------------------

        private void Awake()
        {
            if (projector == null) projector = GetComponentInChildren<DecalProjector>();
            if (projector == null)
            {
                Debug.LogError("[BuildRangeIndicator] No DecalProjector found. Add one as a " +
                               "child of this GameObject.");
                enabled = false;
                return;
            }

            // Start hidden; visibility is updated each frame.
            projector.enabled = false;
        }

        private void Start()
        {
            cachedBuilder = GetComponentInParent<Builder>();
            if (cachedBuilder == null)
            {
                Debug.LogError("[BuildRangeIndicator] No Builder found in parents. " +
                               "Disabling indicator.");
                enabled = false;
                return;
            }

            // Hide for non-owners — other players don't see your range indicator.
            if (!cachedBuilder.IsOwner)
            {
                enabled = false;
                if (projector != null) projector.enabled = false;
                return;
            }

            // Size the projector to match the builder's range (diameter = 2 * range).
            // Modern URP DecalProjector exposes width/height/pivot as separate properties
            // rather than a single Vector3 size. Width and Height are the ground-plane extents
            // of the projection; pivot.z is the volume's depth offset (0 = volume centered
            // on the projector position, projecting equally above and below).
            float diameter = cachedBuilder.BuildRange * 2f;

            // The DecalProjector exposes a `size` Vector3 on its API even though the
            // inspector splits it into Width/Height/ProjectionDepth — assignment is still
            // valid in current URP. We use it here to set all three at once.
            projector.size = new Vector3(diameter, diameter, projectionDepth);
            projector.pivot = new Vector3(0f, 0f, 0f);

            // Center the projection volume on the builder. The decal projector projects
            // along its local +Z axis by default; rotate to project downward (look down).
            //
            // CRITICAL: rotate the PROJECTOR's transform, not this component's transform.
            // BuildRangeIndicator lives on the Builder root (so it can find Builder via
            // GetComponentInParent), but `transform` here is the Builder's transform —
            // rotating it tips the cylinder onto its side. The projector lives on a child
            // GameObject; that's the one that needs the 90° X rotation.
            projector.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
            projector.transform.localPosition = Vector3.zero;
        }

        private void Update()
        {
            if (cachedBuilder == null) return;

            bool shouldShow = IsLocalPlayerPlacing();
            if (projector.enabled != shouldShow)
                projector.enabled = shouldShow;
        }

        // ----- Helpers ----------------------------------------------------

        private bool IsLocalPlayerPlacing()
        {
            if (cachedPlacementController == null)
            {
                cachedPlacementController =
                    UnityEngine.Object.FindAnyObjectByType<TowerPlacementController>();
                if (cachedPlacementController == null) return false;
            }
            return cachedPlacementController.IsPlacing;
        }
    }
}