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

public class blockSpawn : MonoBehaviour
{
    [SerializeField]
    public Inventory.Data[] spawnLogicList;
    public List<ClientData> ConnectedClients;
    public ClientList clientDataList;
    public Block[] SpawnBlocks;
    public List<Vector3> spawnedLocations;
    int scoreDifference = 0;
    float average = 0;

    void Awake()
    {
        ConnectedClients = clientDataList.ConnectedClients;
        SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.is_Walkable).ToArray();
        spawnedLocations = new List<Vector3>();
    }

    public void Spawn()
    {
        getPlayerScores();
        getPlayerLocations(ConnectedClients.ToArray(), 0.75f);

        //second spawning block only if needed
       /* if (scoreDifference > average)
        {
            List<ClientData> lessClients = new List<ClientData>(ConnectedClients);
            lessClients.RemoveAt(lessClients.Count - 1);
            getPlayerLocations(lessClients.ToArray(), 0.6f);
        }*/
    }

    private void getPlayerScores()
    {
        ConnectedClients.Sort((b, a) => a.SceneScore.CompareTo(b.SceneScore));
        int totalScores = 0;
        scoreDifference = ConnectedClients[0].SceneScore + ConnectedClients[ConnectedClients.Count-1].SceneScore;
        Debug.Log("score difference " + scoreDifference);

        for(int i = 0; i < ConnectedClients.Count; i++)
        {
            totalScores += ConnectedClients[i].SceneScore;
        }
        average = totalScores / ConnectedClients.Count;
        Debug.Log("score average " + average);
    }

    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 bool checkValid(Vector3 spawnposition)
    {
        for (int i = 0; i < SpawnBlocks.Length; i++)
        {
            if (SpawnBlocks[i].position.x == spawnposition.x && SpawnBlocks[i].position.z == spawnposition.z)
            {
                return true;
            }
        }
        return false;
    }

    private void spawnBlock(Vector3 spawnposition)
    {
        GameObject prefab = Resources.Load("Logic Block") as GameObject;
        GameObject block = Instantiate(prefab);

        int number = (int)Random.Range(1.0f, spawnLogicList.Length);
        block.GetComponent<LogicCollectable_Multiplayer>().Collectable.element = spawnLogicList[number].element;
        block.GetComponent<LogicCollectable_Multiplayer>().Collectable.Count = spawnLogicList[number].Count;
        block.transform.position = spawnposition;
        Debug.Log("Instantiated new logic block: " + spawnLogicList[number].element + " at position: " + block.transform.position);
        spawnedLocations.Add(spawnposition);
    }

    private void checkLocation(Vector3 spawnposition)
    {
        bool duplicate = false;
        if (duplicate == false)
        {
            bool valid = checkValid(spawnposition);
            if (valid == true)
            {
                spawnBlock(spawnposition);
            }
            else
            {
                Block clostest = Utility.minBy(SpawnBlocks, p => Vector3.Distance(p.transform.position, spawnposition));
                checkLocation(new Vector3(clostest.position.x, clostest.position.y + 1.5f, clostest.position.z));
            }
        }
        else
        {
            //this needs to be changed
            Block clostest = Utility.minBy(SpawnBlocks, p => Vector3.Distance(p.transform.position, spawnposition));
            checkLocation(new Vector3(clostest.position.x, clostest.position.y + 1.5f, clostest.position.z));
        }
    }

    private void getPlayerLocations(ClientData[] clients, float weightMultiplier)
    {
        float[] weightings = new float[clients.Length];
        if(clients.Length > 1)
        {
            Vector3 spawnposition = new Vector3(0, 0, 0);
            for (int i = 0; i < clients.Length; i++)
            {
                spawnposition += clients[i].playerCharacter.CurrentBlock.VisualPosition;
                Debug.Log("currentBlock.VisualPosition " + clients[i].playerCharacter.CurrentBlock.VisualPosition);
            }
            spawnposition *= (1.0f / clients.Length);
            Debug.Log("spawnposition " + spawnposition);

            Vector3[] direction = new Vector3[clients.Length];
            for (int i = 0; i < clients.Length; i++)
            {
                direction[i] = (spawnposition - clients[i].playerCharacter.CurrentBlock.VisualPosition);

                Debug.Log("direction " +  i + " " + direction[i]);
            }

            //weighting calculations
            float[] difAvg = new float[clients.Length];
            for (int i = 0; i < clients.Length; i++)
            {
                difAvg[i] = clients[i].SceneScore - average;
            }

            float[] ratio = new float[clients.Length];

            Debug.Log("difAvg[0] " + difAvg[0]);

            if (difAvg[0] == 0)
            {
                for (int i = 0; i < clients.Length; i++)
                {
                    weightings[i] = 0.5f * weightMultiplier;
                    Debug.Log("weightings " + i + " " + weightings[i]);
                }
            }
            else
            {
                for (int i = 0; i < clients.Length; i++)
                {
                    ratio[i] = difAvg[i] / difAvg[0];
                    ratio[i] /= 2.0f;
                    ratio[i] += 0.5f;
                    weightings[i] = ratio[i] * weightMultiplier;
                    weightings[i] = Mathf.Clamp(weightings[i], 0, 1);
                    Debug.Log("weightings " + i + " " + weightings[i]);
                }
            }

            //multiply weightings by the direction
            //take average point and add directions
            for (int i = 0; i < clients.Length; i++)
            {
                spawnposition += (weightings[i] * direction[i]);
                Debug.Log("(weightings[i] * direction[i] " + (weightings[i] * direction[i]));
            }
            Debug.Log("spawnposition " + spawnposition);
            //spawn first block
            checkLocation(spawnposition);
        }
        else
        {
            Vector2 playerOne = new Vector2(clients[0].playerCharacter.CurrentBlock.VisualPosition.x, clients[0].playerCharacter.CurrentBlock.VisualPosition.z);
            int xVal = (int)Random.Range(-3.0f, 3.0f) + (int)playerOne.x;
            int zVal = (int)Random.Range(-3.0f, 3.0f) + (int)playerOne.y;
            checkLocation(new Vector3(xVal, 1.0f, zVal));
        }
    }
}