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

/// <summary>
/// GAME 1303 Tier 7 — What the pet does when you're not touching it: idle, wander, sleep,
/// react. Cozy Critters ("the pet can idly walk").
///
/// SETUP
///  1. Pet: Sprite + Rigidbody2D (Gravity 0) + Collider2D + Tier 5 TopDownMover
///     (AI Controlled ✓) + Animator + Tier 1 PlayerAnimatorBridge + this script.
///  2. Drag in the NeedStats you want it to react to (energy for sleeping, hunger for
///     begging). All optional — with none assigned it just idles and wanders.
///  3. Wander Area: a BoxCollider2D (trigger) marking where it may walk, or leave empty
///     and it stays within Wander Radius of where it started. Rhys's "one area" fits either.
///  4. Timings are ranges so it doesn't feel robotic: it idles 2-5s, then walks 1-3s, etc.
///  5. Animator: the bridge drives Speed. Add bools "IsSleeping" and "IsHappy" if you want
///     dedicated animations — the brain sets them if they exist.
///
/// STATES
///   Idle    – stands, occasionally looks around
///   Wander  – walks to a random nearby point
///   Sleep   – when energy is low; energy refills while sleeping
///   React   – a short burst after being fed/played with (set by CareAction)
///
/// The pet never does anything punishing. Low needs make it slower and sadder, not dead.
/// </summary>
public class PetBrain : MonoBehaviour
{
    public enum State { Idle, Wander, Sleep, React }

    [Header("Needs (all optional)")]
    public NeedStat energy;
    public NeedStat happiness;
    public NeedStat hunger;

    [Header("Wandering")]
    public BoxCollider2D wanderArea;
    public float wanderRadius = 3f;
    public Vector2 idleTimeRange = new Vector2(2f, 5f);
    public Vector2 walkTimeRange = new Vector2(1f, 3f);
    public float arriveDistance = 0.2f;

    [Header("Sleeping")]
    [Tooltip("Falls asleep when energy drops below this (0-1). 0 = never sleeps.")]
    [Range(0f, 1f)] public float sleepBelowEnergy = 0.2f;
    [Tooltip("Wakes when energy climbs above this.")]
    [Range(0f, 1f)] public float wakeAboveEnergy = 0.8f;
    public float energyRestoredPerMinute = 20f;

    [Header("Mood affects movement")]
    [Tooltip("Speed multiplier when happiness is at zero.")]
    [Range(0.1f, 1f)] public float sadSpeedMultiplier = 0.6f;

    [Header("Events")]
    public UnityEvent<State> OnStateChanged;
    public UnityEvent OnFellAsleep;
    public UnityEvent OnWokeUp;

    public State CurrentState { get; private set; } = State.Idle;

    private TopDownMover mover;
    private Animator anim;
    private Vector2 homePosition;
    private Vector2 target;
    private float stateTimer;
    private float baseSpeed;

    static readonly int SleepHash = Animator.StringToHash("IsSleeping");
    static readonly int HappyHash = Animator.StringToHash("IsHappy");
    private bool hasSleep, hasHappy;

    void Awake()
    {
        mover = GetComponent<TopDownMover>();
        anim = GetComponent<Animator>();
        if (mover != null) { mover.aiControlled = true; baseSpeed = mover.moveSpeed; }
        if (anim != null)
            foreach (var p in anim.parameters)
            {
                if (p.nameHash == SleepHash) hasSleep = true;
                if (p.nameHash == HappyHash) hasHappy = true;
            }
    }

    void Start()
    {
        homePosition = transform.position;
        EnterState(State.Idle);
    }

    void Update()
    {
        // Mood -> speed
        if (mover != null && happiness != null)
            mover.moveSpeed = baseSpeed * Mathf.Lerp(sadSpeedMultiplier, 1f, happiness.Normalized);

        if (hasHappy && happiness != null) anim.SetBool(HappyHash, happiness.Normalized > 0.6f);

        // Sleep overrides everything
        if (energy != null && sleepBelowEnergy > 0f)
        {
            if (CurrentState != State.Sleep && energy.Normalized <= sleepBelowEnergy) { EnterState(State.Sleep); return; }
            if (CurrentState == State.Sleep && energy.Normalized >= wakeAboveEnergy) { EnterState(State.Idle); return; }
        }

        stateTimer -= Time.deltaTime;

        switch (CurrentState)
        {
            case State.Idle:
                mover?.SetMoveInput(Vector2.zero);
                if (stateTimer <= 0f) EnterState(State.Wander);
                break;

            case State.Wander:
                Vector2 toTarget = target - (Vector2)transform.position;
                if (toTarget.magnitude < arriveDistance || stateTimer <= 0f) EnterState(State.Idle);
                else mover?.SetMoveInput(toTarget.normalized);
                break;

            case State.Sleep:
                mover?.SetMoveInput(Vector2.zero);
                energy?.Add(energyRestoredPerMinute / 60f * Time.deltaTime);
                break;

            case State.React:
                mover?.SetMoveInput(Vector2.zero);
                if (stateTimer <= 0f) EnterState(State.Idle);
                break;
        }
    }

    void EnterState(State s)
    {
        if (s == CurrentState && s != State.Idle && s != State.Wander) return;

        bool wasAsleep = CurrentState == State.Sleep;
        CurrentState = s;

        switch (s)
        {
            case State.Idle:
                stateTimer = Random.Range(idleTimeRange.x, idleTimeRange.y);
                break;
            case State.Wander:
                target = PickWanderTarget();
                stateTimer = Random.Range(walkTimeRange.x, walkTimeRange.y);
                break;
            case State.Sleep:
                OnFellAsleep?.Invoke();
                break;
            case State.React:
                stateTimer = 1.5f;
                break;
        }

        if (hasSleep) anim.SetBool(SleepHash, s == State.Sleep);
        if (wasAsleep && s != State.Sleep) OnWokeUp?.Invoke();
        OnStateChanged?.Invoke(s);
    }

    Vector2 PickWanderTarget()
    {
        if (wanderArea != null)
        {
            Bounds b = wanderArea.bounds;
            return new Vector2(Random.Range(b.min.x, b.max.x), Random.Range(b.min.y, b.max.y));
        }
        return homePosition + Random.insideUnitCircle * wanderRadius;
    }

    /// <summary>CareAction calls this so the pet perks up when you interact with it.</summary>
    public void React()
    {
        if (CurrentState == State.Sleep && energy != null && energy.Normalized < wakeAboveEnergy) return;
        EnterState(State.React);
    }

    void OnDrawGizmosSelected()
    {
        Gizmos.color = new Color(0.5f, 1f, 0.8f, 0.5f);
        if (wanderArea != null) Gizmos.DrawWireCube(wanderArea.bounds.center, wanderArea.bounds.size);
        else Gizmos.DrawWireSphere(Application.isPlaying ? (Vector3)homePosition : transform.position, wanderRadius);
    }
}