using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
using Networking.Server;
using Networking;


public class GameManager : MonoBehaviour
{
    #region Inspector Field
    [Header("Settings")]
    [SerializeField]
    private float AnimationTime;
    [SerializeField]
    private GameMode CurrentGameMode;


    [Header("References")]
    [SerializeField]
    [Tooltip("Prefab of character for players to play")]
    private Character characterPrefab;

    [SerializeField]
    private ServerObject server;

    [SerializeField]
    private ClientList ClientList;

    #endregion Inspector Field


    #region Private Variables
    private Dictionary<int, PlayerData> playerData;
    #endregion Private Variables

    public void Awake()
    {
        RegisterHandlers();
        SpawnCharacters();
    }

    private void Update()
    {
        server.ServerUpdate();
    }

    private void RecieveLogicList(NetworkMessage msg)
    {
        LogicProtocols.LogicMsg logicMsg;
        if (!msg.TryRead(out logicMsg))
        {
            Debug.Log("Recieved unknown message");
            return;
        }

        Debug.Log("Recieved function from " + msg.conn.connectionId);

        playerData[msg.conn.connectionId].blockReader.LogicChain = new List<LogicBlock>(logicMsg.elements);
        playerData[msg.conn.connectionId].recievedList = true;

        if (playerData.All(p => p.Value.recievedList))
            StartRound();
    }

    private void StartRound()
    {
        Debug.Log("Starting Round");
        StartCoroutine(RoundRoutine());
    }


    private IEnumerator RoundRoutine()
    {

        playerData.ForEach(p => p.Value.recievedList = false);

        while (playerData.Any(p => !p.Value.blockReader.Finished))
        {

            foreach (PlayerData player in playerData.Values)
            {
                if (!player.waiting)
                {
                    player.waiting = player.blockReader.Read(player.character, AnimationTime);
                }
            }

            yield return new WaitForSeconds(AnimationTime);

            foreach(KeyValuePair<int,PlayerData> player in playerData)
            {
                ClientData client = ClientList.ConnectedClients.First(p => p.ID == player.Key);
                CurrentGameMode.OnPlayerFinishedMove(player.Value.character, client, player.Value.character.CurrentBlock);
            }

            if (playerData.All(p => p.Value.waiting))
            {
                playerData.ForEach(p => p.Value.waiting = false);
                Debug.Log("Finished one move");
            }
        }

        CurrentGameMode.OnRoundFinished();
        CurrentGameMode.isGameOver();

        Debug.Log("Finished Moving");
    }



    private void SpawnCharacters()
    {
        playerData = new Dictionary<int, PlayerData>();
        Block[] SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isSpawnable).ToArray();


        int spawnIndex = 0;
        foreach (ClientData client in ClientList)
        {
            Character newChar = Instantiate(characterPrefab);
            Block startingBlock = SpawnBlocks[(spawnIndex++ % ClientList.ConnectedClients.Count)];
            newChar.Initialise(startingBlock, client.Inventory, client.characterAnimal);
            playerData.Add(client.ID, new PlayerData(newChar,client));
        }
    }

    private void RegisterHandlers()
    {
        server.server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList);
    }




    
}

public class PlayerData
{
    public Character character;
    public BlockReader blockReader;
    public ClientData client;

    public bool recievedList;
    public bool waiting;

    public PlayerData(Character character, ClientData client)
    {
        this.character = character;
        this.client = client;
        blockReader = new BlockReader();
    }
}
