using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// GAME 1303 Tier 5 — Crossy Road traffic. Spawns things at one end of a lane that travel
/// across and despawn at the other. Last Delivery's wasteland hazards and roaming monsters.
///
/// SETUP
///  1. Empty GameObject placed at the START of the lane (where things appear).
///  2. Direction & Lane Length: the arrow gizmo shows where they travel. Objects are
///     destroyed after Lane Length units.
///  3. Prefabs: drag in one or more (a truck, a mutant, a rolling barrel). Each spawn
///     picks one at random — give a prefab more entries to make it more common.
///  4. Timing: Interval with Interval Variance for irregular traffic. Start Delay
///     staggers parallel lanes so they don't all fire together.
///  5. Speed with Speed Variance. Tick Face Direction to flip/rotate the sprite.
///  6. Max Alive caps how many exist at once.
///  7. The spawned object needs its own DamageOnContact (or a monster script) — this
///     script only moves things; it doesn't decide what they do on contact.
///
/// For Chris's "monsters try to intercept you", mix two lanes: fast straight-line traffic
/// (this script) plus a couple of Tier 2 EnemyChase monsters that actually hunt. The
/// contrast between predictable and unpredictable threats is what makes the route a puzzle.
/// </summary>
public class LaneSpawner : MonoBehaviour
{
    [Header("Lane")]
    public Vector2 direction = Vector2.right;
    public float laneLength = 24f;

    [Header("What")]
    public List<GameObject> prefabs = new List<GameObject>();
    public int maxAlive = 6;

    [Header("When")]
    public float startDelay = 0f;
    public float interval = 2f;
    public float intervalVariance = 0.5f;
    public bool spawnOnStart = true;

    [Header("How fast")]
    public float speed = 4f;
    public float speedVariance = 1f;
    public bool faceDirection = true;
    [Tooltip("Rotate the sprite (vehicles) instead of flipping it (creatures).")]
    public bool rotateInsteadOfFlip = false;
    public float rotationOffset = 0f;

    [Header("Events")]
    public UnityEvent<GameObject> OnSpawned;

    private readonly List<GameObject> alive = new List<GameObject>();

    void Start()
    {
        if (spawnOnStart) StartCoroutine(SpawnLoop());
    }

    IEnumerator SpawnLoop()
    {
        yield return new WaitForSeconds(startDelay);
        while (true)
        {
            alive.RemoveAll(o => o == null);
            if (alive.Count < maxAlive) Spawn();
            yield return new WaitForSeconds(Mathf.Max(0.1f, interval + Random.Range(-intervalVariance, intervalVariance)));
        }
    }

    public void Spawn()
    {
        if (prefabs.Count == 0) return;
        var prefab = prefabs[Random.Range(0, prefabs.Count)];
        if (prefab == null) return;

        var obj = Instantiate(prefab, transform.position, Quaternion.identity);
        Vector2 dir = direction.normalized;
        float spd = Mathf.Max(0.1f, speed + Random.Range(-speedVariance, speedVariance));

        if (faceDirection)
        {
            if (rotateInsteadOfFlip)
                obj.transform.rotation = Quaternion.Euler(0f, 0f, Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg + rotationOffset);
            else if (dir.x < 0f)
            {
                Vector3 s = obj.transform.localScale; s.x *= -1f; obj.transform.localScale = s;
            }
        }

        // Give it a mover. A Rigidbody2D is used if present (so it can collide properly).
        var rb = obj.GetComponent<Rigidbody2D>();
        if (rb != null)
        {
            rb.gravityScale = 0f;
            rb.linearVelocity = dir * spd;
        }
        else
        {
            var mover = obj.AddComponent<LaneTraveller>();
            mover.velocity = dir * spd;
        }

        // Clean up at the far end
        var life = obj.AddComponent<LaneDespawner>();
        life.origin = transform.position;
        life.maxDistance = laneLength;

        alive.Add(obj);
        OnSpawned?.Invoke(obj);
    }

    void OnDrawGizmos()
    {
        Gizmos.color = new Color(1f, 0.4f, 0.2f, 0.9f);
        Vector3 d = ((Vector3)direction.normalized) * laneLength;
        Gizmos.DrawLine(transform.position, transform.position + d);
        Gizmos.DrawWireSphere(transform.position, 0.25f);
        Gizmos.DrawWireCube(transform.position + d, Vector3.one * 0.3f);
    }
}