using UnityEngine;
using TD.Core;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace TD.Levels
{
    /// <summary>
    /// Authoring volume marking where enemies spawn into a player's zone. Spawner tiles are
    /// <see cref="PlacementState.Restricted"/> in the baked grid (no tower placement allowed)
    /// but remain walkable so enemies can leave the spawner.
    /// </summary>
    /// <remarks>
    /// A zone may have multiple spawners; <see cref="spawnerIdInZone"/> disambiguates them.
    /// Player 5 in the 9-player Wintermaul map is the canonical multi-spawner zone.
    ///
    /// The spawner declares an owning player via <see cref="owner"/> rather than relying on
    /// spatial containment within a PlayerZoneVolume. The bake validates (with a soft warning)
    /// that the spawner's tiles fall inside its declared owner's zone.
    /// </remarks>
    public class SpawnerVolume : VolumeBase
    {
        [Tooltip("Which player's zone owns this spawner. Explicit — not inferred from spatial overlap.")]
        public PlayerSlot owner = PlayerSlot.Player1;

        [Tooltip("Disambiguator for zones with multiple spawners. Should be 0 for single-spawner zones, " +
                 "and contiguous starting from 0 for multi-spawner zones (e.g., 0 and 1).")]
        public int spawnerIdInZone = 0;

        [Tooltip("Direction enemies face when they spawn. Used for visual orientation and may bias " +
                 "initial enemy movement direction.")]
        public Direction spawnFacing = Direction.South;

        [Tooltip("Whether tiles in this volume are buildable. Defaults to Invalid (no placement on spawners).")]
        public PlacementValidity placementValidity = PlacementValidity.Invalid;

        // Spawners draw above player zones so the player zone color reads as background.
        private const float FillYLevel = 0.06f;
        private const float ArrowYLevel = 0.07f;
        private const float ArrowLength = 1.5f; // 1.5 tiles per gizmo design

        protected override bool GetAlwaysShowToggle(LevelAuthoring authoring)
        {
            return authoring.alwaysShowSpawners;
        }

        private void OnDrawGizmosSelected()
        {
            DrawGizmosCore();
        }

        private void OnDrawGizmos()
        {
            if (ShouldDrawAlwaysOn())
            {
                DrawGizmosCore();
            }
        }

        private void DrawGizmosCore()
        {
            Color baseColor = PlayerColors.Get(owner);
            DrawTileCoverageFill(baseColor, alpha: 0.40f, yLevel: FillYLevel);
            DrawRectangularOutline(baseColor, yLevel: FillYLevel);

            // Direction arrow originates from the volume's center and extends 1.5 tiles in the
            // declared facing direction, rendered in opaque owner color.
            var col = Collider;
            if (col != null)
            {
                Vector3 arrowOrigin = new Vector3(col.bounds.center.x, ArrowYLevel, col.bounds.center.z);
                Vector3 arrowDir = DirectionToWorld(spawnFacing);
                DrawArrow(arrowOrigin, arrowDir, ArrowLength, baseColor);
            }

#if UNITY_EDITOR
            // Label conditional on multi-spawner status:
            //   - Single-spawner zone: "Player N Spawn"
            //   - Multi-spawner zone:  "Player N Spawn 0", "Player N Spawn 1", etc.
            // Multi-spawner detection scans other SpawnerVolumes in the scene with the same owner.
            // Same posture as the leak-exit target lookup: cheap on realistic maps, can be cached
            // if it ever shows up as an editor-perf issue.
            if (col != null)
            {
                Vector3 labelPos = new Vector3(col.bounds.center.x, ArrowYLevel + 0.1f, col.bounds.center.z);
                string labelText = ZoneHasMultipleSpawners()
                    ? $"{FormatPlayerName(owner)} Spawn {spawnerIdInZone}"
                    : $"{FormatPlayerName(owner)} Spawn";
                Handles.Label(labelPos, labelText);
            }
#endif
        }

        /// <summary>
        /// Returns true if more than one active SpawnerVolume in the scene shares this spawner's
        /// <see cref="owner"/>. Used to decide whether to suffix the gizmo label with the spawner ID.
        /// </summary>
        private bool ZoneHasMultipleSpawners()
        {
            var spawners = Object.FindObjectsByType<SpawnerVolume>(FindObjectsInactive.Exclude);
            if (spawners == null) return false;

            int count = 0;
            for (int i = 0; i < spawners.Length; i++)
            {
                if (spawners[i] == null) continue;
                if (spawners[i].owner == owner)
                {
                    count++;
                    if (count > 1) return true;
                }
            }
            return false;
        }
    }
}