using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;

/// <summary>
/// GAME 1303 Tier 6 — Detective Liz's flashlight. Aims, drains a battery, recharges only
/// while you stand still (Jax's class idea), and hurts ghosts caught in the beam.
///
/// SETUP — the light
///  1. Install URP and set up 2D lighting: Edit -> Project Settings -> Graphics with a
///     URP asset, and add a Global Light 2D to the scene set DARK (e.g. 0.15 intensity)
///     — that's what makes the building dark in the first place.
///  2. On the player, create a child "Flashlight" with a Light 2D component set to
///     Spot (Freeform's "Point" type with narrow inner/outer angles). Drag it into Beam Light.
///  3. Add this script to the PLAYER. Drag the Flashlight child into Beam Transform.
///
/// SETUP — the beam as a weapon
///  4. On the same Flashlight child, add a Polygon/Cone-shaped Collider2D (Is Trigger)
///     roughly matching the light cone, plus a Tier 2 Hitbox (Target Team = Enemy,
///     Repeat Delay ~0.5). Drag it into Beam Hitbox. LightSensitiveEnemy reacts to it.
///
/// SETUP — the battery
///  5. Add a Tier 3 FuelSystem to the player for the battery and drag it in — or leave it
///     empty and the flashlight never runs out (fine for early testing).
///  6. Recharge Requires Standing Still is the interesting rule: the player has to stop
///     and be vulnerable to get light back. Recharge Rate is battery per second.
///
/// AIM MODES
///   Mouse    – points at the cursor (best on PC).
///   Facing   – points where the player faces (simplest, gamepad friendly).
///   Stick    – right stick / Move vector.
/// </summary>
public class Flashlight2D : MonoBehaviour
{
    public enum Aim { Mouse, Facing, Stick }

    [Header("Beam")]
    public Transform beamTransform;
    [Tooltip("The Light 2D GameObject (any renderer/light — it's just enabled/disabled).")]
    public GameObject beamLight;
    public Hitbox beamHitbox;
    public Aim aim = Aim.Mouse;
    public float aimSmoothing = 12f;
    public float rotationOffset = 0f;

    [Header("Battery")]
    public FuelSystem battery;
    public float drainPerSecond = 4f;
    public bool rechargeRequiresStandingStill = true;
    public float rechargeRate = 8f;
    [Tooltip("Must stand still this long before recharging starts.")]
    public float rechargeDelay = 0.5f;
    [Tooltip("Battery level below which the beam flickers as a warning (0-1).")]
    [Range(0f, 1f)] public float flickerBelow = 0.2f;

    [Header("Control")]
    public bool startOn = true;
    [Tooltip("Toggle with the Interact-adjacent 'Flashlight' action, or hold it.")]
    public bool toggleMode = true;

    [Header("Feedback")]
    public string clickSfx = "flashlight_click";
    public string emptySfx = "flashlight_empty";

    [Header("Events")]
    public UnityEvent OnTurnedOn;
    public UnityEvent OnTurnedOff;
    public UnityEvent OnBatteryEmpty;
    public UnityEvent<bool> OnRechargingChanged;

    public bool IsOn { get; private set; }
    public bool IsRecharging { get; private set; }

    private PlayerController2D platformer;
    private TopDownMover topDown;
    private Vector2 moveInput;
    private Vector2 aimDirection = Vector2.right;
    private float stillTimer;
    private bool held;

    void Awake()
    {
        platformer = GetComponent<PlayerController2D>();
        topDown = GetComponent<TopDownMover>();
        SetOn(startOn);
    }

    void OnMove(InputValue v) { moveInput = v.Get<Vector2>(); }

    void OnFlashlight(InputValue v)
    {
        if (toggleMode) { if (v.isPressed) SetOn(!IsOn); }
        else { held = v.isPressed; SetOn(held); }
    }

    void Update()
    {
        UpdateAim();
        UpdateBattery();
    }

    void UpdateAim()
    {
        if (beamTransform == null) return;

        Vector2 desired = aimDirection;
        switch (aim)
        {
            case Aim.Mouse:
                if (Mouse.current != null && Camera.main != null)
                {
                    Vector3 m = Camera.main.ScreenToWorldPoint(Mouse.current.position.ReadValue());
                    Vector2 d = (Vector2)m - (Vector2)transform.position;
                    if (d.sqrMagnitude > 0.01f) desired = d.normalized;
                }
                break;
            case Aim.Stick:
                if (moveInput.sqrMagnitude > 0.1f) desired = moveInput.normalized;
                break;
            default:
                if (platformer != null) desired = platformer.Facing;
                else if (topDown != null) desired = topDown.Facing2D;
                break;
        }

        aimDirection = aimSmoothing > 0f
            ? Vector2.Lerp(aimDirection, desired, aimSmoothing * Time.deltaTime).normalized
            : desired;

        float angle = Mathf.Atan2(aimDirection.y, aimDirection.x) * Mathf.Rad2Deg + rotationOffset;
        // The beam is a child of a sprite that may be flipped on X — undo that so the
        // beam doesn't point backwards when the player faces left.
        float flip = Mathf.Sign(transform.lossyScale.x);
        beamTransform.rotation = Quaternion.Euler(0f, 0f, flip >= 0f ? angle : 180f - angle);
    }

    void UpdateBattery()
    {
        bool moving = moveInput.sqrMagnitude > 0.01f;
        stillTimer = moving ? 0f : stillTimer + Time.deltaTime;

        if (battery == null) return;

        if (IsOn)
        {
            if (!battery.Consume(drainPerSecond * Time.deltaTime))
            {
                SetOn(false);
                if (!string.IsNullOrEmpty(emptySfx)) AudioManager.Instance?.PlaySFX(emptySfx);
                OnBatteryEmpty?.Invoke();
            }
            else if (flickerBelow > 0f && battery.Normalized < flickerBelow && beamLight != null)
            {
                beamLight.SetActive(Random.value > 0.25f);
            }
            SetRecharging(false);
            return;
        }

        // Off: recharge, maybe only while standing still
        bool canRecharge = !rechargeRequiresStandingStill || (stillTimer >= rechargeDelay);
        SetRecharging(canRecharge && battery.Normalized < 1f);
        if (IsRecharging) battery.Refill(rechargeRate * Time.deltaTime);
    }

    void SetRecharging(bool on)
    {
        if (on == IsRecharging) return;
        IsRecharging = on;
        OnRechargingChanged?.Invoke(on);
    }

    public void SetOn(bool on)
    {
        if (on && battery != null && battery.IsEmpty) on = false;
        if (on == IsOn && Application.isPlaying) return;

        IsOn = on;
        if (beamLight != null) beamLight.SetActive(on);
        if (beamHitbox != null) beamHitbox.gameObject.SetActive(on);
        if (!string.IsNullOrEmpty(clickSfx)) AudioManager.Instance?.PlaySFX(clickSfx);
        if (on) OnTurnedOn?.Invoke(); else OnTurnedOff?.Invoke();
    }

    /// <summary>Is a world position inside the beam? DarknessMeter and ghosts use this.</summary>
    public bool IsLit(Vector3 worldPos, float coneAngle = 35f, float range = 8f)
    {
        if (!IsOn) return false;
        Vector2 to = (Vector2)worldPos - (Vector2)transform.position;
        if (to.magnitude > range) return false;
        return Vector2.Angle(aimDirection, to) <= coneAngle;
    }
}