using UnityEngine;
using UnityEngine.InputSystem;

using Bytes;

public class GameManager : MonoBehaviour
{
    [SerializeField] private PlayerInput controls;
    [SerializeField] private CannonScript[] cannonList;
    [SerializeField] private UIController uiController;
    [SerializeField] private WorldSwitcher worldSwitcher;

    [Header("Game Variables")]
    [SerializeField, ReadOnly] private GameState state;
    [SerializeField, ReadOnly] private float points;
    [field: SerializeField, ReadOnly] public int CurrentDimensionID { get; private set; }
    [SerializeField] private int[] IDLayerList;

    public static GameManager Instance { get; private set; }

    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
        }
        else
        {
            Instance = this;
            state = GameState.InGame;
            points = 0f;

            CurrentDimensionID = worldSwitcher.CurrentWorldIndex;
            worldSwitcher.OnChangeWorld.AddListener((int newDimensionID)=> 
            {
                CurrentDimensionID = newDimensionID;
                uiController.SetCurrentDimension(CurrentDimensionID, DimensionController.STARTING_HP, DimensionController.STARTING_HP);
                Debug.Log("Changed dimension to: " + newDimensionID + "!");
            });

            // Vive le spaghetti 🍝🍝🍝
            uiController.SetCurrentDimension(CurrentDimensionID, 
                DimensionController.STARTING_HP, 
                DimensionController.STARTING_HP);
            uiController.UpdatePointsText(points);
            
            SoundManager.Instance.SwitchMusicLayer(1);
        }
    }

    public void DealDamage(int dimensionID, float hp, float maxHP) 
    {
        uiController.SetDimensionHP(CurrentDimensionID, dimensionID, hp, maxHP);

        // Check loss condition
        if (hp <= 0) 
            TriggerGameOver(dimensionID);
    }

    private void TriggerGameOver(int dimensionID)
    {
        if (state == GameState.Loss) return;
        
        // Stop controls
        controls.SwitchCurrentActionMap("UI");
        
        // Show Game Over Message
        Debug.Log("Game Over: Dimension " + dimensionID + " has been destroyed");
        
        // Show Options (Return to Menu / Retry)
        state = GameState.Loss;
    }
    
    public bool OnUpgrade(Upgrade selectedUpgrade)
    {
        if (!(points >= selectedUpgrade.GetCost())) return false;
        points -= selectedUpgrade.GetCost();
        uiController.UpdatePointsText(points);
        return true;
    }

    public void UpgradeFireRate(FireRateUpgrade upgrade)
    {
        foreach (var cannon in cannonList)
        {
            cannon.SetFireRate(upgrade.GetFireRate());
        }
    }

    public void UpgradeDamage(DamageUpgrade upgrade)
    {
        foreach (var cannon in cannonList)
        {
            cannon.SetDamage(upgrade.GetDamage());
        }

    }

    public void UpgradeBullets(BulletsAmountUpgrade upgrade)
    {
        foreach (var cannon in cannonList)
        {
            cannon.SetBullets(upgrade.GetBullets());
        }
    }
    
    public float GetPoints()
    {
        return points;
    }

    public void SetPoints(float nPoints)
    {
        points = nPoints;
        uiController.UpdatePointsText(points);
    }

    public void SpendPoints(float amount)
    {
        if (amount > points) return;
        points -= amount;
        uiController.UpdatePointsText(points);
    }

    public void GainPoints(float amount)
    {
        points += amount;
        uiController.UpdatePointsText(points);

        EventManager.Dispatch(EventNames.GainCurrency, new IntDataBytes((int)amount));
    }

    public LayerMask GetCurrentDimensionLayerMask()
    {
        return LayerMask.GetMask(LayerMask.LayerToName(IDLayerList[CurrentDimensionID]));
    }

   public int GetCurrentLayerID()
    {
        return IDLayerList[CurrentDimensionID];
    }

}

public enum GameState
{
    InGame,
    Loss,
}