using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Networking.Server;
using TMPro;
using UnityEngine.UI;

[CreateAssetMenu(menuName = "Major Project/GameModes/Color Collide", order = 201)]
public class ColorGameMode : GameMode
{

    public int MaxRound = 5;
    public string nextScene = "ServerTestScene";
    List<ClientData> ConnectedClients;
    public Material OverlayMaterial;
    public float scrollSpeed = 0.0f; //The rate at which the level will scroll past


    public int RoundCount { get; private set; }
    private Dictionary<ClientData, List<Block>> BlocksOwned;

    /// <summary>
    /// Called once all players have finished their moves but before the Objective is checked
    /// </summary>
    protected override void OnRoundEnd(PlayerData[] allPlayers)
    {
        //Move the camera forward at a steady rate each round
        if (scrollSpeed > 0.0f)
        {
            Camera.main.transform.Translate(scrollSpeed, 0, 0, Space.World);
            Debug.Log("New camera position at x = " + Camera.main.transform.position.x);
        }
        else
        {
            Debug.Log("Not scrolling");
        }

        //At the end of each round, any stuck players are freed to resume moving next round
        foreach (PlayerData player in allPlayers)
        {
            player.character.stuck = false;

            if (player.character.inPit)
            {
                player.character.respawnCharacter();
            }
        }

        RoundCount++;
    }


    /// <summary>
    /// Checks if the Game is finished
    /// </summary>
    /// <returns>returns if game is finished</returns>
    public override bool isGameOver(PlayerData[] allPlayers)
    {
        return (RoundCount >= MaxRound -1);
    }


    /// <summary>
    /// Called once per player after they have moved onto a block
    /// </summary>
    /// <param name="character">Character which moved</param>
    /// <param name="client">Client of the character</param>
    /// <param name="currentBlock">Block moved onto</param>
    protected override void OnPlayerMoved(Character character, ClientData client, Block currentBlock)
    {
        handleFalling(character, client, currentBlock, character.justMoved);

        /*Debug.Log("Moved to square at " + currentBlock.transform.position.x + ", "
             + currentBlock.transform.position.y + ", "
              + currentBlock.transform.position.z);

        //If a character has fallen in the water or into a pit, we mark that fact, and they lose the rest of their turn
        character.inWater = currentBlock.isWater;
        character.inPit = currentBlock.isPit;

        if (character.inWater == true || character.inPit == true)
        {
            character.stuck = true;
        }

        Debug.Log("inWater = " + character.inWater + ", inPit = " + character.inPit + ", stuck = " + character.stuck);*/

        //Commented out because we don't do this in the racetrack mode

        /*ClientData OwnedClient;
        Material overlay = null;
        if (isOwned(currentBlock, out OwnedClient))
        {
            if (OwnedClient == client)
                return;

            BlocksOwned[OwnedClient].Remove(currentBlock);

            foreach (Material mat in currentBlock.GetComponent<Renderer>().materials)
            {
                if (mat.name == OverlayMaterial.name + " (Instance)")
                    overlay = mat;
            }
        }

        if (overlay == null)
        {
            overlay = new Material(OverlayMaterial);
            List<Material> mats = new List<Material>(currentBlock.GetComponent<Renderer>().materials);
            mats.Add(overlay);
            currentBlock.GetComponent<Renderer>().materials = mats.ToArray();
        }

        overlay.SetColor("_NewColor", client.Color);

        if (!BlocksOwned.ContainsKey(client))
            BlocksOwned.Add(client, new List<Block>());

        BlocksOwned[client].Add(currentBlock);
         
        if (overlay != null)
            currentBlock.StartCoroutine(AnimateBlock(overlay, 0.25f));*/
    }

    protected override void OnRoundStart(PlayerData[] allPlayers)
    {
        
    }

    protected override void OnAllPlayersMoved(PlayerData[] allPlayers)
    {
        foreach (PlayerData player in allPlayers)
        {
            /*  The justMoved variable is used to determine whether a player taking their turn in the water should become stuck
             *  (because they moved into/in the water), or not (because they're turning while remaining in the same square)
             *  It's not needed from move to move, so we clear it
                */
            player.character.justMoved = false;
        }
    }

    protected override void OnGameOver(PlayerData[] allPlayers)
    {
        throw new System.NotImplementedException();
    }

    private bool isOwned(Block block, out ClientData client)
    {
        client = null;

        foreach (KeyValuePair<ClientData, List<Block>> ownedList in BlocksOwned)
        {
            if (ownedList.Value.Contains(block))
            {
                client = ownedList.Key;
                return true;
            }
        }

        return false;
    }

    private void handleFalling(Character character, ClientData client, Block currentBlock, bool didMove)
    {
        //If a character has fallen in the water or into a pit, we mark that fact, and they lose the rest of their turn
        character.inWater = currentBlock.isWater;
        character.inPit = currentBlock.isPit;

        if (didMove && (character.inWater || character.inPit))
        {
            character.stuck = true;
        }
        Debug.Log("inWater = " + character.inWater + ", inPit = " + character.inPit + ", stuck = " + character.stuck);
    }
    protected override void OnPlayerKilled(Character character, ClientData client)
    {
        if (character.inPit)
        {
            character.lives -= 1;
            character.ClientLink.Lives = character.lives;
        }
    }

    private IEnumerator AnimateBlock(Material mat, float time)
    {

        float timeElasped = 0;

        while (timeElasped < time)
        {
            mat.SetFloat("_Multiplier", (timeElasped / time));
            yield return new WaitForEndOfFrame();

            timeElasped += Time.deltaTime;
        }

        mat.SetFloat("_Multiplier", 1);
    }

    protected override void OnGameStart(PlayerData[] allPlayers)
    {
        BlocksOwned = new Dictionary<ClientData, List<Block>>();
        RoundCount = 0;
        for(int i = 0; i < allPlayers.Length; i++)
        {
            OnPlayerMoved(allPlayers[i].character, allPlayers[i].client, allPlayers[i].character.CurrentBlock);
        }
    }

    public override PlayerData[] getPlayerOrder(PlayerData[] AllPlayers)
    {
        throw new System.NotImplementedException();
    }
}
