using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class OpponentDragSpawner : MonoBehaviour, IRoundCallback, IManaChangeCallback, IDragDropListener
{

    [SerializeField] Opponent opponent;
    [SerializeField] Color disabledPreviewSpriteColor = new Color(0.5f, 0.5f, 0.5f, 1f);
    [SerializeField] Color disabledCostTextColor = Color.red;
    [SerializeField] List<AudioClip> spawnOpponentSfx;

    int placedOpponentCount = 0;
    bool currentlyPlacingNew = false;

    Image previewSprite;
    Text costText;
    Color defaultCostTextColor;
    BaseCameraController cameraController;

    void Start()
    {
        previewSprite = transform.Find("OpponentImage").GetComponent<Image>();
        costText = transform.Find("Cost").GetComponent<Text>();
        defaultCostTextColor = costText.color;
        previewSprite.sprite = opponent.enemySprite;
        cameraController = Camera.main.GetComponent<BaseCameraController>();

        var eventTrigger = GetComponent<EventTrigger>();

        var beginDragEvent = new EventTrigger.Entry();
        beginDragEvent.eventID = EventTriggerType.BeginDrag;
        beginDragEvent.callback.AddListener((data) => OnBeginDrag((PointerEventData)data));
        eventTrigger.triggers.Add(beginDragEvent);

        StatsManager.instance.manaChangeCallbacks.Add(this);
        RoundController.instance.roundCallbacks.Add(this);
        DragDestroyController.instance.listeners.Add(this);

        UpdateDisplayStates();
    }

    void OnBeginDrag(PointerEventData eventData)
    {
        if (RoundController.instance.roundRunning || !StatsManager.instance.ModifyMana(GetNextOpponentCost()))
        {
            return;
        }
        var newEnemy = Instantiate(opponent.enemyPrefab);
        DragDestroyController.instance.HandoffEnemy(newEnemy);
        cameraController.PlayRandomGlobalAudioClip(spawnOpponentSfx);
        placedOpponentCount++;
        currentlyPlacingNew = true;
        UpdateDisplayStates();
    }

    void UpdateDisplayStates()
    {
        // Enemies call `OnEnemyDeleted()` when they are destroyed. This also happens
        // when exiting the game though. This is probably a hacky solution, but w/e
        if (costText.IsDestroyed())
        {
            return;
        }
        var nextCost = GetNextOpponentCost();
        costText.text = (-nextCost).ToString();
        var canBuy = StatsManager.instance.CanModifyMana(nextCost);
        previewSprite.color = canBuy && !RoundController.instance.roundRunning ? Color.white : disabledPreviewSpriteColor;
        costText.color = canBuy ? defaultCostTextColor : disabledCostTextColor;
    }

    int GetNextOpponentCost()
    {
        return (int)(-opponent.enemyCost * Mathf.Pow(1 + opponent.costMultiplier, placedOpponentCount));
    }

    void RecalculatePlacedOpponentsCount()
    {
        placedOpponentCount = 0;
        foreach (var enemy in RoundController.instance.placedEnemies)
        {
            if (enemy.opponentType == opponent)
            {
                placedOpponentCount++;
            }
        }
        UpdateDisplayStates();
    }

    public void OnEnemyPlaced(GameObject enemy, Opponent opponent, bool validPosition)
    {
        if (opponent == this.opponent)
        {
            if (!validPosition && currentlyPlacingNew)
            {
                // Enemy placed in invalid position; will be destroyed and refunded
                Destroy(enemy);
                placedOpponentCount--;
                StatsManager.instance.ModifyMana(-GetNextOpponentCost());
            }
            currentlyPlacingNew = false;
            UpdateDisplayStates();
        }
    }

    public void OnEnemyDeleted(GameObject enemy, Opponent opponent)
    {
        if (opponent == this.opponent)
        {
            placedOpponentCount--;
            StatsManager.instance.ModifyMana(-GetNextOpponentCost());
            UpdateDisplayStates();
        }
    }

    public void OnRoundStart()
    {
        UpdateDisplayStates();
    }

    public void OnRoundEnd(bool won)
    {
        // To make sure this is called _after_ enemies might have destroyed itself in this callback
        Invoke(nameof(RecalculatePlacedOpponentsCount), 0.01f);
        UpdateDisplayStates();
    }

    public void OnManaChanged(int oldValue, int newValue)
    {
        UpdateDisplayStates();
    }

}