﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using Random = UnityEngine.Random;

public class BattleManager : MonoBehaviour
{
    [SerializeField] YoutubeChatReader _youtubeChatReader;
    [SerializeField] BattleSettings _settings;
    [SerializeField] SideLine _sideLine;
    [SerializeField] bool _startGame;
    [SerializeField] TMP_Text _timeToStart;
 
    public static BattleManager Instance { get; private set; }
    public BattleState BattleState = BattleState.WaitingForPlayers;
    public int PlayerCount => FindObjectsOfType<Battler>(false).Length;

    List<string> players = new();
    Queue<string> _nextPlayers = new();

    public BattleArena[] BattleArenas;
    public BattleArena[] SemiFinalArenas;
    public BattleArena FinalArena;

    void OnValidate()
    {
        _sideLine = FindObjectOfType<SideLine>();
        BattleArenas = FindObjectsOfType<BattleArena>();
    }

    void Awake()
    {
        Instance = this;
        Settings = _settings;
    }


    IEnumerator Start()
    {
	    yield return null;
        
        if (Settings.GetYoutubePlayers)
	        yield return WaitForYoutubePlayers();
        else
        {
            _nextPlayers = new Queue<string>(players);
            _sideLine.Bind(_nextPlayers);
            _sideLine.UpdateSideline();
        }
        
        while (!_startGame)
            yield return null;

        if (Settings.RandomizeOrderEntry)
            _nextPlayers = new Queue<string>(players.OrderBy(t => Random.Range(0f, float.MaxValue)));
        else
            _nextPlayers = new Queue<string>(players);

        _sideLine.Bind(_nextPlayers);
        _sideLine.UpdateSideline();

        SetBattleState(BattleState.CharactersAtStart);
        
        yield return BeginNextBattle();
    }

    void SetBattleState(BattleState state)
    {
        BattleState = state;
    }

    public void AddToContest(string playerName)
    {
	    if (BattleState != BattleState.WaitingForPlayers)
		    return;

	    if (players.Contains(playerName))
	    {
		    _sideLine.UpdateSideline();
		    return;
	    }
            

	    players.Add(playerName);
	    _nextPlayers.Enqueue(playerName);
	    _timeToStart.SetText($"{playerName} entered the arena.");
        
	    _sideLine.UpdateSideline();
    }

    IEnumerator WaitForYoutubePlayers()
    {
	    _nextPlayers = new Queue<string>();
	    _sideLine.Bind(_nextPlayers);
	    _sideLine.UpdateSideline();

	    players = new List<string>();
	    _youtubeChatReader.gameObject.SetActive(true);
	    _timeToStart.SetText("Choose your character to join! (say 'rat') in chat");

	    if (!_startGame)
	    {
		    Debug.Log("Waiting for Players");
		    while (!_startGame)
			    yield return null;
	    }

	    for (int secondsToStart = 4; secondsToStart >= 0; secondsToStart--)
	    {
		    _timeToStart.SetText($"Closing Entry in {secondsToStart}");
		    yield return new WaitForSeconds(1f);
	    }
	    
	    _youtubeChatReader.gameObject.SetActive(false);
    }

    public void StartGame() => _startGame = true;


    IEnumerator PreviewRound()
    {
        Debug.Log("Starting Next Round");

        yield return new WaitForSeconds(Settings.DelayBetweenRounds);
        
        float timer = 1f;

        RemovePastWinnersFromArenas();
        while (timer > 0f)
        {
            _timeToStart.SetText("ROUND WINNERS!");
            timer -= Time.deltaTime;
            yield return null;
        }

        yield return BeginNextBattle();
    }

    IEnumerator BeginNextBattle()
    {
        float timer = 10f;
        PrepareNextBattlers();
        _sideLine.UpdateSideline();

        while (timer > 0f)
        {
            _timeToStart.SetText($"Next Round in {Math.Round(timer, MidpointRounding.AwayFromZero)}");
            timer -= Time.deltaTime;
            yield return new WaitForSeconds(1f);
            timer -= 1f;
        }

        BeginBattle();
        _timeToStart.SetText($"FIGHT");
        yield return new WaitForSeconds(2f);
        _timeToStart.SetText(string.Empty);
    }

    void RemovePastWinnersFromArenas()
    {
        foreach (var arena in BattleArenas)
            arena.RemovePastBattlers();
    }

    void PrepareNextBattlers()
    {
        if (_nextPlayers.Count < 4)
        {
            string left = NextBattler();
            string right = NextBattler();
            FinalArena.NextBattle(left, right);
        }
        else if (_nextPlayers.Count < 6)
        {
            foreach (var arena in SemiFinalArenas)
            {
                string left = NextBattler();
                string right = NextBattler();
                arena.NextBattle(left, right);
            }
        }
        else
        {
            foreach (var arena in BattleArenas)
            {
                if (arena == FinalArena || SemiFinalArenas.Contains(arena))
                    continue;

                if (_nextPlayers.Count <= 1)
                {
                    arena.gameObject.SetActive(false);
                }
                else
                {
                    string left = NextBattler();
                    string right = NextBattler();
                    arena.NextBattle(left, right);
                }
            }
        }

        SetBattleState(BattleState.CharactersAtStart);
    }

    void BeginBattle()
    {
        foreach (var arena in BattleArenas)
        {
            arena.BeginBattle();
        }

        SetBattleState(BattleState.Fighting);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.KeypadPlus))
            Application.targetFrameRate++;
        if (Input.GetKeyDown(KeyCode.KeypadMinus))
            Application.targetFrameRate--;
        
        if (BattleState == BattleState.Fighting &&
            BattleArenas.All(t => t.isActiveAndEnabled == false || t.Battling == false))
        {
            if (_nextPlayers.Count == 1)
            {
                _timeToStart.SetText($"WINNER - {_nextPlayers.First()}");
                SetBattleState(BattleState.FightOverResults);
                return;
            }

            SetBattleState(BattleState.FightOverResults);
            StartCoroutine(PreviewRound());
        }
    }

    public static BattleSettings Settings { get; private set; }

    public string NextBattler() => _nextPlayers.Dequeue();

    public List<string> GetNextBattlers() =>
        _nextPlayers != null ? _nextPlayers.Take(8).ToList() : new List<string>() {"nobody"};

    public void AddWinner(Battler winner)
    {
        _nextPlayers.Enqueue(winner.PlayerName);
        //_sideLine.UpdateSideline();
        //_sideLine.AddPlayer(winner.PlayerName);
    }

    public void SetText(string text)
    {
        _timeToStart.SetText(text);
    }
}