using System;
using Actions;
using Grid;
using UnityEngine;
using UnityEngine.Serialization;

public class Unit : MonoBehaviour {
    [FormerlySerializedAs("ACTION_POINTS_MAX")] [SerializeField]
    private int actionPointsMax = 2;

    [SerializeField] private bool isEnemy;
    private int actionPoints;

    public GridPosition GridPosition { get; private set; }
    public BaseAction[] BaseActionArray { get; private set; }
    public HealthSystem HealthSystem { get; private set; }

    public int ActionPoints {
        get => actionPoints;
        private set {
            actionPoints = value;
            OnAnyActionPointsChanged?.Invoke(this, EventArgs.Empty);
        }
    }

    public bool IsEnemy => isEnemy;

    private void Awake() {
        BaseActionArray = GetComponents<BaseAction>();
        HealthSystem = GetComponent<HealthSystem>();
        actionPoints = actionPointsMax;
    }

    private void Start() {
        GridPosition = LevelGrid.Instance.GetGridPosition(transform.position);
        LevelGrid.Instance.AddUnitAtGridPosition(GridPosition, this);
        TurnSystem.Instance.OnTurnChanged += TurnSystem_OnTurnChanged;
        HealthSystem.OnDead += HealthSystem_OnDead;
        OnAnyUnitSpawned?.Invoke(this, EventArgs.Empty);
    }

    private void Update() {
        GridPosition newGridPosition = LevelGrid.Instance.GetGridPosition(transform.position);
        if (newGridPosition == GridPosition) return;
        GridPosition oldGridPosition = GridPosition;
        GridPosition = newGridPosition;
        LevelGrid.Instance.UnitMovedGridPosition(this, oldGridPosition, GridPosition);
    }

    public static event EventHandler OnAnyUnitSpawned;
    public static event EventHandler OnAnyUnitDead;

    public T GetAction<T>() where T : BaseAction {
        foreach (BaseAction baseAction in BaseActionArray) {
            if (baseAction is T action) return action;
        }

        return null;
    }

    private void HealthSystem_OnDead(object sender, EventArgs e) {
        LevelGrid.Instance.RemoveUnitAtGridPosition(GridPosition, this);
        Destroy(gameObject);
        OnAnyUnitDead?.Invoke(this, EventArgs.Empty);
    }

    public static event EventHandler OnAnyActionPointsChanged;

    private void TurnSystem_OnTurnChanged(object sender, EventArgs e) {
        if (IsEnemy ^ TurnSystem.Instance.IsPlayerTurn || TurnSystem.Instance.IsPlayerTurn ^ IsEnemy) {
            ActionPoints = actionPointsMax;
        }
    }

    public bool TrySpendActionPointsToTakeAction(BaseAction baseAction) {
        if (!CanSpendActionPointsToTakeAction(baseAction)) return false;
        SpendActionPoints(baseAction.ActionPointsCost);
        return true;
    }

    private bool CanSpendActionPointsToTakeAction(BaseAction baseAction) => ActionPoints >= baseAction.ActionPointsCost;

    private void SpendActionPoints(int amount) => ActionPoints -= amount;

    public void Damage(int damageAmount) => HealthSystem.Damage(damageAmount);

    public Vector3 GetWorldPosition() => transform.position;
}