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

public class blockSpawn : MonoBehaviour
{
    [SerializeField]
    public Inventory.Data[] StrongLogicList;
    public Inventory.Data[] NormalLogicList;
    public Inventory.Data[] WeakLogicList;
    Inventory.Data[] listtoUse;

    List<ClientData> ConnectedClients;
    public ClientList clientDataList;
    public List<Block> SpawnBlocks;
    List<Vector3> spawnedLocations;
    public List<Block> possibleSpawnLocations;
    int spawnNumber = 2;
    public int min_x, max_x;

    void Awake()
    {
        ConnectedClients = clientDataList.ConnectedClients;        
        spawnedLocations = new List<Vector3>();
        possibleSpawnLocations = new List<Block>();
    }
    public void wakeup()
    {
        SpawnBlocks.Clear();
        SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isCollectableSpawnable).ToList();
    }

    public void Spawn()
    {
        //Sort play locations so leader is first
        if (ConnectedClients.Count > 1)
        {
            ConnectedClients.Sort((b, a) => a.playerCharacter.transform.position.x.CompareTo(b.playerCharacter.transform.position.x));
        }

        min_x = (int)ConnectedClients[ConnectedClients.Count - 1].playerCharacter.transform.position.x;
        max_x = (int)ConnectedClients[0].playerCharacter.transform.position.x + 4;

        Debug.Log("count before update " + SpawnBlocks.Count);
        updatePlayerPositions();
        Debug.Log("count mid update " + SpawnBlocks.Count);
        updatePositions(min_x - 1);
        Debug.Log("count after update " + SpawnBlocks.Count);

        //Check points within the bounds of players
        possibleSpawnLocations.Clear();
        foreach (Block point in SpawnBlocks)
        {
            //Debug.Log("Position: " + point.transform.position.x + " and " + point.transform.position.z);
            if(point.transform.position.x >= min_x && point.transform.position.x <= max_x)
            {
                possibleSpawnLocations.Add(point);
            }
        }

        //pick a random value from those available, checks the location
        //then removes it to remove the possibility of duplicates
        Debug.Log("possibleSpawnLocations count " + possibleSpawnLocations.Count);

        int triesCount = 0;

        if(possibleSpawnLocations.Count > 0)
        {
            while (spawnNumber > 0 && triesCount < 25)
            {
                if(possibleSpawnLocations.Count > 0){
                    int choice = Random.Range(0, possibleSpawnLocations.Count - 1);
                    bool spawned = checkLocation(possibleSpawnLocations[choice].transform.position);
                    if (spawned == true)
                    {
                        possibleSpawnLocations.RemoveAt(choice);
                        triesCount = 0;
                        spawnNumber--;
                    }else{
                        triesCount++;
						continue;
					}
                }
                else
                {
                    goto escape;
                }
                //Debug.Log("spawnNumber " + spawnNumber);
            }
            //Debug.Log("SpawnTries: " + triesCount);
        }
        escape:
        spawnNumber = 2;
    }

    private bool checkLocation(Vector3 spawnposition)
    {
        bool duplicate = checkDuplicatePosition(spawnposition);
        if (duplicate == false)
        {
            spawnBlock(spawnposition);
            //Debug.Log("spawned at" + spawnposition);
            return true;
        }
        else
        {
            //Debug.Log("Fail to spawn at " + spawnposition);
            return false;
        }
    }

    private bool checkDuplicatePosition(Vector3 spawnposition)
    {
        if (spawnedLocations.Count > 0)
        {
            for (int k = 0; k < spawnedLocations.Count; k++)
            {
                if (spawnedLocations[k].x == spawnposition.x && spawnedLocations[k].z == spawnposition.z)
                {
                    return true;
                }
            }
        }
        return false;
    }

    private void spawnBlock(Vector3 spawnposition)
    {
        GameObject prefab = Resources.Load("Logic Block") as GameObject;
        GameObject block = Instantiate(prefab);
        spawnposition.y = 1.0f;
        block.transform.position = spawnposition;
        spawnedLocations.Add(spawnposition);
    }

    public void assignLogicBlock(GameObject block, float value)
    {
        if(value > 1)
        {
            listtoUse = WeakLogicList;
        }
        else if (value <= 1 && value > (-4))
        {
            listtoUse = NormalLogicList;
        }
        else if (value <= (-5))
        {
            listtoUse = StrongLogicList;
        }
        //max behind camera is -6/-7
        //max lives = 3
        // ~ anyone ahead of the average will have a minimum of 4(full lives) or 2(with 1 life left)
        // ~ anyone behind the average will have a minimum of -3-4(full lives) or -5/-6 (with one life left)

        int number = Random.Range(0, listtoUse.Length-1);
        block.GetComponent<LogicCollectable_Multiplayer>().Collectable.element = listtoUse[number].element;
        block.GetComponent<LogicCollectable_Multiplayer>().Collectable.Count = 1;
    }

    public void updatePositions(int min)
    {
        for(int i = SpawnBlocks.Count -1; i>=0; i--)
        {
            if(SpawnBlocks[i].transform.position.x <= min)
            {
                Debug.Log("block to remove position x: " + SpawnBlocks[i].transform.position.x);
                SpawnBlocks.Remove(SpawnBlocks[i]);
            }
        }
    }

    public void updatePlayerPositions()
    {
        for (int i = SpawnBlocks.Count - 1; i >= 0; i--)
        {
            if (SpawnBlocks[i].CurrentPlayer != null)
            {
                SpawnBlocks.Remove(SpawnBlocks[i]);
            }
        }
    }
}