using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using UnityEngine;
using static CustomerController;
using Random = UnityEngine.Random;


public class CustomerManager : MonoBehaviour {
    public static CustomerManager Instance { get; private set; }


    [SerializeField] private GameObject _customerPrefab;
    [SerializeField] private Transform _customerSpawnPoint;

    [SerializeField] private float _timeToNextCustomerMin = 5;
    [SerializeField] private float _timeToNextCustomerMax = 10;
        
    private List<SellCounter> _sellCounters = new List<SellCounter>();
    private List<SellCounter> AvailableCounters { get; } = new List<SellCounter>();
    
    private readonly List<CustomerController> _customers = new List<CustomerController>();

    private int _newCustomerNeeded; // 0 = no new ones needed, > 0 = new one needed
    private float _timeToNextCustomer;


    //Args for the event
    public class OnCustomerLeftArgs : EventArgs {
        public bool Angry;
    }
    
    public event EventHandler<OnCustomerLeftArgs> OnCustomerLeft;    

    // Start is called before the first frame update
    private void Start() {
        // Find all sellingCounters in the scene
        
        if (Instance != null) {
            Debug.LogError("What? 2 CustomerManagers crazy!!!");
        }

        Instance = this;
        
        var sellCounters = FindObjectsOfType<SellCounter>();
        foreach (var sellCounter in sellCounters) {
            sellCounter.OnCounterStartSelling += CounterStartedSelling;
            _sellCounters?.Add(sellCounter);
        }

      
    }

    private void CounterStartedSelling(object sender, [NotNull] SellCounter.OnCounterStartSellingArgs e) {
        if (e == null) throw new ArgumentNullException(nameof(e));
        // Spawn a customer at the spawn point
        _newCustomerNeeded += 1;
        AvailableCounters.Add(e.SellCounter);
    }

    private void SpawnCustomer(SellCounter target) {
        var customer = Instantiate(_customerPrefab, _customerSpawnPoint.position, Quaternion.identity);
        var customerController = customer.GetComponent<CustomerController>();

        customerController.SetTargetCounter(target);
        customerController.SetExitPosition(_customerSpawnPoint.position);

        customerController.OnCustomerLeft += CustomerLeft;
        _customers.Add(customerController);
    }

    private void CustomerLeft(SellCounter sellCounter, CustomerController customerController) {
        if (customerController.State == Customer.MoodState.Angry) {
            //Customer left angry, should dispach a new customer to the counter
            _newCustomerNeeded += 1;
            if (!AvailableCounters.Contains(sellCounter)) {
                AvailableCounters.Add(sellCounter);
            }
            else {
                Debug.LogError("This should not happen, the counter is already in the available list");
            }
        }
        OnCustomerLeft?.Invoke(this, new OnCustomerLeftArgs { Angry = customerController.State == Customer.MoodState.Angry });
    }


    // Update is called once per frame
    private void Update() {
        if(AvailableCounters.Count == 0) return;
        if (_newCustomerNeeded > 0) {
            _timeToNextCustomer -= Time.deltaTime;
            if (_timeToNextCustomer <= 0) {
                _newCustomerNeeded--;
                _timeToNextCustomer = Random.Range(_timeToNextCustomerMin, _timeToNextCustomerMax);

                SellCounter target = AvailableCounters[Random.Range(0, AvailableCounters.Count)];
                SpawnCustomer(target);

                AvailableCounters.Remove(target);
            }
        }
    }

    public void StoppedSelling(SellCounter sellCounter) {
        if (AvailableCounters.Contains(sellCounter)) {
            AvailableCounters.Remove(sellCounter);
        }

        //Check if any customer has this counter as an target
        foreach (var customerController in _customers) {
            if (customerController.TargetCounter != sellCounter) continue;
            
            customerController.SetDestination(_customerSpawnPoint.position);
            customerController.SetState(CustomerState.WalkingToExit);
        }
    }

    public void CustomerDies([NotNull] CustomerController customerController) {
        if (customerController == null) return;
        if (_customers.Contains(customerController)) {
            _customers.Remove(customerController);
        }
    }
}