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

/// <summary>
/// GAME 1303 Tier 4 — A piston that slams down, holds, then rises slowly. Cutthroat Course.
///
/// SETUP
///  1. Parent "Crusher" (empty) at the TOP of the shaft — the resting position. This script here.
///  2. Child "Head": the block sprite + BoxCollider2D (Is Trigger ON — the player
///     shouldn't be able to ride it) + DamageOnContact (Instant Kill ✓). Drag into Head.
///  3. Slam Distance: how far down it travels, OR tick Auto Distance to raycast down on
///     Ground Layer and stop just above the floor.
///  4. Timing: Wait At Top → (Warning: rumble) → Slam (fast) → Hold At Bottom → Rise (slow).
///     Start Delay staggers a row of crushers.
///  5. Damage only while slamming and holding — a rising crusher is safe to walk under.
///
/// Also the "vertical spikes/pillars" in Nicholas's sketch can be Crushers with a spike sprite.
/// </summary>
public class Crusher : MonoBehaviour
{
    public Transform head;
    public float slamDistance = 4f;
    public bool autoDistance = true;
    public LayerMask groundLayer;

    [Header("Timing")]
    public float startDelay = 0f;
    public float waitAtTop = 1.5f;
    public float warningTime = 0.4f;
    public float slamSpeed = 25f;
    public float holdAtBottom = 0.6f;
    public float riseSpeed = 3f;

    [Header("Feel")]
    public float rumbleAmount = 0.04f;
    public string slamSfx = "crusher_slam";
    public string warningSfx = "";
    public UnityEvent OnSlammed;   // camera shake, dust particles

    private Vector3 topLocal;
    private Vector3 bottomLocal;
    private DamageOnContact damage;

    void Start()
    {
        if (head == null) { Debug.LogWarning("Crusher: assign the Head child."); enabled = false; return; }
        damage = head.GetComponent<DamageOnContact>();
        topLocal = head.localPosition;

        float dist = slamDistance;
        if (autoDistance)
        {
            var col = head.GetComponent<Collider2D>();
            float halfH = col != null ? col.bounds.extents.y : 0.5f;
            RaycastHit2D hit = Physics2D.Raycast(head.position, Vector2.down, 50f, groundLayer);
            if (hit.collider != null) dist = Mathf.Max(0.1f, hit.distance - halfH);
        }
        bottomLocal = topLocal + Vector3.down * dist;

        if (damage) damage.enabled = false;
        StartCoroutine(Loop());
    }

    IEnumerator Loop()
    {
        yield return new WaitForSeconds(startDelay);
        while (true)
        {
            yield return new WaitForSeconds(Mathf.Max(0f, waitAtTop - warningTime));

            // Warning rumble
            if (!string.IsNullOrEmpty(warningSfx)) AudioManager.Instance?.PlaySFX(warningSfx);
            float t = 0f;
            while (t < warningTime)
            {
                t += Time.deltaTime;
                head.localPosition = topLocal + (Vector3)Random.insideUnitCircle * rumbleAmount;
                yield return null;
            }
            head.localPosition = topLocal;

            // Slam
            if (damage) damage.enabled = true;
            yield return MoveTo(bottomLocal, slamSpeed);
            if (!string.IsNullOrEmpty(slamSfx)) AudioManager.Instance?.PlaySFX(slamSfx);
            OnSlammed?.Invoke();

            yield return new WaitForSeconds(holdAtBottom);

            // Rise
            if (damage) damage.enabled = false;
            yield return MoveTo(topLocal, riseSpeed);
        }
    }

    IEnumerator MoveTo(Vector3 target, float speed)
    {
        while (Vector3.Distance(head.localPosition, target) > 0.01f)
        {
            head.localPosition = Vector3.MoveTowards(head.localPosition, target, speed * Time.deltaTime);
            yield return null;
        }
        head.localPosition = target;
    }

    void OnDrawGizmosSelected()
    {
        if (head == null) return;
        Gizmos.color = Color.red;
        Vector3 top = Application.isPlaying ? transform.TransformPoint(topLocal) : head.position;
        Gizmos.DrawLine(top, top + Vector3.down * slamDistance);
    }
}