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);
}
}