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

/// <summary>
/// GAME 1303 Tier 7 — The checkout. Customers queue, the player stands behind it and
/// presses a key to scan each item, then the customer pays and leaves. Store Simulator.
///
/// SETUP
///  1. Register model + a BoxCollider + this script.
///  2. Queue Start: an empty child in front of the register. Queue Spacing sets how far
///     apart shoppers stand — the queue builds backwards from there.
///  3. Player Stand Zone: a trigger BoxCollider behind the register. The player must be
///     inside it to serve, which is what makes running the shop a physical job rather
///     than a menu.
///  4. Scanning: each press of the Interact key scans one item (Scan Time throttles it).
///     When the basket is done the sale completes, StoreEconomy.Earn is called, and the
///     customer leaves happy.
///  5. Wire OnCustomerWaiting to a bell sound — that's the cue to stop stocking and go
///     serve, and it's the core tension of the genre.
///
/// Auto Serve is there for early testing: tick it and sales happen on their own so Sanad
/// can check the economy before building the interaction.
/// </summary>
public class Register : MonoBehaviour
{
    [Header("Queue")]
    public Transform queueStart;
    public float queueSpacing = 0.8f;
    public Vector3 queueDirection = Vector3.back;
    public int maxQueue = 6;

    [Header("Serving")]
    public Collider playerStandZone;
    public float scanTime = 0.4f;
    public bool autoServe = false;
    public float autoServeDelay = 2f;

    [Header("Feedback")]
    public string scanSfx = "beep";
    public string cashSfx = "cash";

    [Header("Events")]
    public UnityEvent<int> OnQueueChanged;
    public UnityEvent OnCustomerWaiting;
    public UnityEvent<float> OnSaleCompleted;    // amount
    public UnityEvent<int, int> OnScanProgress;  // (scanned, total)

    public int QueueLength => queue.Count;
    public CustomerAI CurrentCustomer => queue.Count > 0 ? queue[0] : null;
    public bool PlayerPresent { get; private set; }

    private readonly List<CustomerAI> queue = new List<CustomerAI>();
    private int scanned;
    private float scanCooldown;
    private float autoTimer;

    void Update()
    {
        CheckPlayerPresence();
        scanCooldown -= Time.deltaTime;

        if (CurrentCustomer == null) { autoTimer = autoServeDelay; return; }

        if (autoServe)
        {
            autoTimer -= Time.deltaTime;
            if (autoTimer <= 0f) { autoTimer = autoServeDelay; CompleteSale(); }
            return;
        }

        if (!PlayerPresent || scanCooldown > 0f) return;
        if (Keyboard.current != null && Keyboard.current.eKey.wasPressedThisFrame) ScanOne();
    }

    void CheckPlayerPresence()
    {
        if (playerStandZone == null) { PlayerPresent = true; return; }
        var p = GameObject.FindGameObjectWithTag("Player");
        PlayerPresent = p != null && playerStandZone.bounds.Contains(p.transform.position);
    }

    void ScanOne()
    {
        var customer = CurrentCustomer;
        if (customer == null) return;

        scanCooldown = scanTime;
        scanned++;
        if (!string.IsNullOrEmpty(scanSfx)) AudioManager.Instance?.PlaySFX(scanSfx);
        OnScanProgress?.Invoke(scanned, customer.Basket.Count);

        if (scanned >= customer.Basket.Count) CompleteSale();
    }

    void CompleteSale()
    {
        var customer = CurrentCustomer;
        if (customer == null) return;

        float amount = customer.BasketValue;
        StoreEconomy.Instance?.Earn(amount);
        if (!string.IsNullOrEmpty(cashSfx)) AudioManager.Instance?.PlaySFX(cashSfx);

        customer.CompletePurchase(amount);
        LeaveQueue(customer);
        OnSaleCompleted?.Invoke(amount);
    }

    // ---- Queue management ----
    public Vector3 GetQueueSpot(CustomerAI customer)
    {
        int index = queue.IndexOf(customer);
        if (index < 0) index = queue.Count;
        Vector3 origin = queueStart != null ? queueStart.position : transform.position;
        return origin + queueDirection.normalized * queueSpacing * index;
    }

    public bool JoinQueue(CustomerAI customer)
    {
        if (queue.Count >= maxQueue || queue.Contains(customer)) return false;
        queue.Add(customer);
        if (queue.Count == 1) { scanned = 0; OnCustomerWaiting?.Invoke(); }
        OnQueueChanged?.Invoke(queue.Count);
        return true;
    }

    public void LeaveQueue(CustomerAI customer)
    {
        if (!queue.Remove(customer)) return;
        scanned = 0;
        OnQueueChanged?.Invoke(queue.Count);
        if (queue.Count > 0) OnCustomerWaiting?.Invoke();

        // Shuffle everyone forward
        for (int i = 0; i < queue.Count; i++)
        {
            var agent = queue[i].GetComponent<UnityEngine.AI.NavMeshAgent>();
            if (agent != null) agent.SetDestination(GetQueueSpot(queue[i]));
        }
    }

    void OnDrawGizmosSelected()
    {
        Vector3 origin = queueStart != null ? queueStart.position : transform.position;
        Gizmos.color = Color.cyan;
        for (int i = 0; i < maxQueue; i++)
            Gizmos.DrawWireSphere(origin + queueDirection.normalized * queueSpacing * i, 0.25f);
    }
}