using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Rift : MonoBehaviour, IPunObservable
{
    [Header("Listeners:")]
    [SerializeField] private GameEventListener_Float experienceOnDeath;
    [Header("Visual Components:")]
    [SerializeField] private GameObject openning;
    [SerializeField] private GameObject maintain;
    [SerializeField] private GameObject closing;

    [Header("Enemies:")]
    [SerializeField] private List<GameObject> enemyPrefabs = new List<GameObject>();
    [Header("Boss Prefabs:")]
    [SerializeField] private List<GameObject> bossPrefabs = new List<GameObject>();
    [Header("Spawnpoint Variations:")]
    [SerializeField] private List<Transform> spawnpoints = new List<Transform>();

    private Dictionary<int, int> enemyType_Quantity;

    PhotonView photonView;

    WaitForSeconds delayBetweenSpawns = new WaitForSeconds(GameConstants.GameBalancing.RiftDelayBetweenSpawns);
    WaitForSeconds delayToClose = new WaitForSeconds(1f);

    UnitDifficultySettings unitDifficultySettings;
    UnitDifficultySetter unitDifficultySetter;
    GameObject spawnedEnemy;

    RiftSettings settings;

    int totalEnemiesPerWave;
    int totalWavesToDefeat = 0;
    bool bossSpawned = false;

    private void Awake()
    {
        photonView = GetComponent<PhotonView>();
        experienceOnDeath.Response.AddListener((x) => CountTowardsBossSpawn());
    }

    public void InitializeRift(RiftSettings settings)
    {
        this.settings = settings;
        
        totalEnemiesPerWave = 0;
        totalWavesToDefeat = settings.numberOfWaves;
        bossSpawned = false;

        enemyType_Quantity = settings.enemyIndexes_Quantity.ToDictionary(entry => entry.Key, entry => entry.Value);
        Debug.Log("Total Types of enemies: " + enemyType_Quantity.Keys.Count);


        unitDifficultySettings = GameDifficultyController.Instance.GetCurrentDifficultySettings();
    }

    public void StartSpawning()
    {
        if (PhotonNetwork.IsMasterClient)
            StartCoroutine(SpawnEnemiesOverTime());
    }

    IEnumerator SpawnEnemiesOverTime()
    {
        SetVisual(0);

        for (int i = 0; i < enemyType_Quantity.Keys.Count; i++)
        {
            totalEnemiesPerWave += enemyType_Quantity[i];
        }

        yield return new WaitForSeconds(0.8f);

        SetVisual(1);

        for (int i = 0; i < enemyType_Quantity.Keys.Count; i++)
        {
            for (int j = 0; j < enemyType_Quantity[i]; j++)
            {
                spawnedEnemy = PhotonNetwork.Instantiate("Enemies/" + enemyPrefabs[i].name, spawnpoints[Random.Range(0, spawnpoints.Count)].position , this.transform.rotation);

                unitDifficultySetter = spawnedEnemy.GetComponentInChildren<UnitDifficultySetter>(true);
                unitDifficultySetter.InitializeUnitDifficulty(unitDifficultySettings);

                yield return delayBetweenSpawns;
            }
        }

        SetVisual(2);

        yield return delayToClose;

        SetVisual(-1);

        //yield return delayBetweenSpawns;

        //DestroyAfterSpawn();
    }

    IEnumerator SpawnBoss()
    {
        yield return delayToClose;

        UpdateScaleForBossSpawn();

        SetVisual(0);

        yield return new WaitForSeconds(0.8f);

        SetVisual(1);

        spawnedEnemy = PhotonNetwork.Instantiate("Bosses/" + bossPrefabs[settings.bossIndex].name, this.transform.position, this.transform.rotation);

        unitDifficultySetter = spawnedEnemy.GetComponentInChildren<UnitDifficultySetter>(true);
        unitDifficultySetter.InitializeUnitDifficulty(unitDifficultySettings);

        yield return delayBetweenSpawns;

        SetVisual(2);

        yield return delayToClose;

        SetVisual(-1);

        yield return delayBetweenSpawns;

        DestroyAfterSpawn();
    }

    private void CountTowardsBossSpawn()
    {
        if (!PhotonNetwork.IsMasterClient) return;

        totalEnemiesPerWave--;
        if (totalEnemiesPerWave > 0) return;

        if (bossSpawned) return;
        totalWavesToDefeat--;
        Debug.Log("All enemies dead, waves defeated decreased to = " + totalWavesToDefeat);
        if (totalWavesToDefeat > 0)
        {
            StartCoroutine(DelayedChangeLocation());
            return;
        }
        Debug.Log("Spawning boss");
        bossSpawned = true;
        StartCoroutine(SpawnBoss());
    }

    private void DestroyAfterSpawn()
    {
        if (PhotonNetwork.LocalPlayer.IsMasterClient)
            PhotonNetwork.Destroy(this.gameObject);
    }

    private IEnumerator DelayedChangeLocation()
    {
        yield return delayToClose;

        ChangeLocation();
    }

    private void ChangeLocation()
    {
        Debug.Log("Changing location and spawning new wave");
        this.transform.position = settings.zoneData.spawnPoints[Random.Range(0, settings.zoneData.spawnPoints.Count)].position;

        StartSpawning();
    }

    private void SetVisual(int index)
    {
        switch (index)
        {
            case -1:
                openning.SetActive(false);
                maintain.SetActive(false);
                closing.SetActive(false);
                break;
            case 0:
                openning.SetActive(true);
                maintain.SetActive(false);
                closing.SetActive(false);
                break;
            case 1:
                openning.SetActive(false);
                maintain.SetActive(true);
                closing.SetActive(false);
                break;
            case 2:
                openning.SetActive(false);
                maintain.SetActive(false);
                closing.SetActive(true);
                break;
            default:
                break;
        }
    }
    private void UpdateScaleForBossSpawn()
    {
        openning.transform.localScale = Vector3.one * 2f;
        maintain.transform.localScale = Vector3.one * 2f;
        closing.transform.localScale = Vector3.one * 2f;

        photonView.RPC(nameof(RPC_ScaleForBoss), RpcTarget.Others);
    }

    [PunRPC]
    private void RPC_ScaleForBoss()
    {
        openning.transform.localScale = Vector3.one * 2f;
        maintain.transform.localScale = Vector3.one * 2f;
        closing.transform.localScale = Vector3.one * 2f;
    }

    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if(stream.IsWriting)
        {
            stream.SendNext(openning.activeSelf);
            stream.SendNext(maintain.activeSelf);
            stream.SendNext(closing.activeSelf);
        }
        if(stream.IsReading)
        {
            openning.SetActive((bool)stream.ReceiveNext());
            maintain.SetActive((bool)stream.ReceiveNext());
            closing.SetActive((bool)stream.ReceiveNext());
        }
    }
}
