using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;

public class Generation : MonoBehaviourPunCallbacks
{
    Dictionary<string, int> weightTable = new Dictionary<string, int>()
    {
        {"FuseIn", 1},
        {"FuseLeft", 10},
        {"FuseRight", 10},
        // {"SplitOut", 1},
        {"SplitRight", 10},
        {"SplitLeft", 10},
        {"Straight", 1},
        {"StraightCurved", 1},
        {"TurnLeft", 2},
        {"TurnRight", 2}
    };

    List<string> keys = new List<string>();

    [SerializeField] List<GameObject> _allRoots = new List<GameObject>();

    [SerializeField] private GameObject _empty;
    [SerializeField] private GameObject _goal;

    [SerializeField] private int _length;
    [SerializeField] private int _width;
    private bool _canSpawn = true;
    [SerializeField] private bool _generate;

    PhotonView view;


    // Start is called before the first frame update
    void Start()
    {
        view = GetComponent<PhotonView>();
    }

    // Update is called once per frame
    void Update()
    {
        if (_generate)
        {
            for (int i = _allRoots.Count - 1; i > 0; i--)
            {
                if (_allRoots[i].name == "Empty")
                {
                    _allRoots.Remove(_allRoots[i]);
                }
                else
                {
                    Destroy(_allRoots[i]);
                }
            }
            _generate = false;
            GenerateMap();
        }
    }

    public override void OnPlayerEnteredRoom(Player other)
    {
        if (PhotonNetwork.CurrentRoom.PlayerCount == PhotonNetwork.CurrentRoom.MaxPlayers && PhotonNetwork.IsMasterClient)
        {
            GenerateMap();
        }
    }

    void GenerateMap()
    {
        _allRoots = new List<GameObject>();
        for (int x = 0; x < _length * 10; x += 10)
        {
            for (float z = 0; z < _width * 3.5; z += 3.5f)
            {
                string[] roots = new string[0];
                GameObject root;
                if (x != 0)
                {
                    int value = 0;
                    value = GetWeightedValue(x, z);
                    roots = keys.ToArray();
                    // print(roots.Length);
                    // print(value);
                    if (keys.Count != 0)
                    {
                        root = (GameObject)Resources.Load(roots[value]);
                    }
                    else
                    {
                        root = _empty;
                    }
                }
                else
                {
                    _canSpawn = true;
                    root = (GameObject)Resources.Load("Straight");
                }

                if (_canSpawn)
                {
                    var spawnedRoot = PhotonNetwork.Instantiate(root.name, new Vector3(x, 0, z), Quaternion.Euler(root.transform.rotation.eulerAngles.x, root.transform.rotation.eulerAngles.y, root.transform.rotation.eulerAngles.z - 90));
                    _allRoots.Add(spawnedRoot);
                }
                else
                {
                    _allRoots.Add(_empty);
                }
            }
        }

        foreach (GameObject g in _allRoots)
        {
            if (g.name != "Empty")
            {
                g.transform.parent = transform;
            }
        }

        transform.localScale *= 10;

        while (transform.childCount > 0)
        {
            transform.GetChild(0).parent = null;
        }

        transform.localScale /= 10;


        var goal = PhotonNetwork.Instantiate(_goal.name, new Vector3(_length * 100 + 55, 0, (_width * 3.5f) / 2), Quaternion.identity);
    }

    private int GetWeightedValue(int x, float z)
    {
        keys = new List<string>();
        #region Rules
        if (x == 10 && z == 0)
        {
            keys.Add("Straight");
            keys.Add("StraightCurved");
            // keys.Add("TurnLeft");
            // keys.Add("FuseRight");
        }
        else
        {
            if (_allRoots[_allRoots.Count - 5].name != "TurnRight(Clone)" && _allRoots[_allRoots.Count - 5].name != "TurnLeft(Clone)" &&
                _allRoots[_allRoots.Count - 1].name != "FuseRight(Clone)" && _allRoots[_allRoots.Count - 1].name != "TurnLeft(Clone)" &&
                _allRoots[_allRoots.Count - 1].name != "SplitLeft(Clone)")
            {
                if (_allRoots[_allRoots.Count - 4].name != "Empty" && z != (_width * 3.5) - 3.5f && _allRoots[_allRoots.Count - 5].name != "Empty" &&
                    _allRoots[_allRoots.Count - 4].name != "TurnRight(Clone)" && _allRoots[_allRoots.Count - 5].name != "FuseRight(Clone)" &&
                    _allRoots[_allRoots.Count - 5].name != "SplitOut(Clone)")
                {
                    keys.Add("FuseRight");
                }

                if (_allRoots[_allRoots.Count - 1].name == "Empty" && _allRoots[_allRoots.Count - 5].name != "Empty" &&
                    _allRoots[_allRoots.Count - 4].name == "Empty" && _allRoots[_allRoots.Count - 5].name != "SplitLeft(Clone)" &&
                    _allRoots[_allRoots.Count - 5].name != "SplitOut(Clone)" && _allRoots[_allRoots.Count - 3].name != "TurnRight(Clone)" &&
                    _allRoots[_allRoots.Count - 4].name != "TurnRight(Clone)" && _allRoots[_allRoots.Count - 3].name != "SplitOut(Clone)" &&
                    z != (_width * 3.5) - 3.5f && _allRoots[_allRoots.Count - 3].name != "SplitRight(Clone)")
                {
                    keys.Add("SplitLeft");
                }

                if (_allRoots[_allRoots.Count - 1].name == "Empty" && (_allRoots[_allRoots.Count - 5].name != "Empty" ||
                    _allRoots[_allRoots.Count - 4].name == "SplitOut(Clone)" || _allRoots[_allRoots.Count - 6].name == "SplitOut(Clone)") &&
                    _allRoots[_allRoots.Count - 5].name != "SplitLeft(Clone)" && _allRoots[_allRoots.Count - 4].name == "Empty" &&
                    _allRoots[_allRoots.Count - 5].name != "SplitOut(Clone)" && _allRoots[_allRoots.Count - 4].name != "TurnRight(Clone)" &&
                    _allRoots[_allRoots.Count - 3].name != "TurnRight(Clone)" && z != (_width * 3.5) - 3.5f && _allRoots[_allRoots.Count - 4].name != "SplitRight(Clone)" &&
                    _allRoots[_allRoots.Count - 3].name != "SplitRight(Clone)")
                {
                    keys.Add("TurnLeft");
                }

                if ((_allRoots[_allRoots.Count - 5].name != "Empty" || _allRoots[_allRoots.Count - 6].name == "SplitLeft(Clone)" ||
                    _allRoots[_allRoots.Count - 4].name == "SplitRight(Clone)" || _allRoots[_allRoots.Count - 4].name == "TurnRight(Clone)"
                    || _allRoots[_allRoots.Count - 6].name == "TurnLeft(Clone)" || _allRoots[_allRoots.Count - 6].name == "SplitLeft(Clone)") &&
                    _allRoots[_allRoots.Count - 1].name != "FuseIn(Clone)" &&
                    _allRoots[_allRoots.Count - 5].name != "SplitOut(Clone)" && _allRoots[_allRoots.Count - 1].name != "SplitOut(Clone)")
                {
                    keys.Add("Straight");
                    keys.Add("StraightCurved");
                }


                if (z != 0 && _allRoots[_allRoots.Count - 1].name == "Empty" && (_allRoots[_allRoots.Count - 5].name != "Empty" ||
                    _allRoots[_allRoots.Count - 4].name == "SplitOut(Clone)" || _allRoots[_allRoots.Count - 6].name == "SplitOut(Clone)") &&
                    _allRoots[_allRoots.Count - 2].name != "SplitOut(Clone)" && _allRoots[_allRoots.Count - 2].name != "TurnRight(Clone)" &&
                    _allRoots[_allRoots.Count - 5].name != "SplitOut(Clone)" && _allRoots[_allRoots.Count - 2].name != "TurnLeft(Clone)" &&
                    _allRoots[_allRoots.Count - 2].name != "SplitLeft(Clone)")
                {
                    keys.Add("TurnRight");
                }

                if (z != 0 && _allRoots[_allRoots.Count - 1].name == "Empty" && _allRoots[_allRoots.Count - 5].name != "Empty" &&
                    _allRoots[_allRoots.Count - 6].name != "Empty" && _allRoots[_allRoots.Count - 2].name != "FuseRight(Clone)" &&
                    _allRoots[_allRoots.Count - 6].name != "TurnRight(Clone)")
                {
                    keys.Add("FuseLeft");
                }

                // if (_allRoots[_allRoots.Count - 1].name == "Empty" && _allRoots[_allRoots.Count - 5].name != "Empty" &&
                //     _allRoots[_allRoots.Count - 6].name == "Empty" && _allRoots[_allRoots.Count - 2].name != "TurnLeft(Clone)" &&
                //     _allRoots[_allRoots.Count - 5].name != "SplitOut(Clone)" && _allRoots[_allRoots.Count - 2].name != "SplitLeft(Clone)" &&
                //     _allRoots[_allRoots.Count - 4].name != "Straight(Clone)" && _allRoots[_allRoots.Count - 4].name != "StraightCurved(Clone)" &&
                //     _allRoots[_allRoots.Count - 5].name != "SplitLeft(Clone)" && z != (_width * 3.5) - 3.5f)
                // {
                //     keys.Add("SplitOut");
                // }
            }



            if (z != 0 && (_allRoots[_allRoots.Count - 5].name != "Empty" || _allRoots[_allRoots.Count - 4].name == "SplitOut(Clone)") &&
                _allRoots[_allRoots.Count - 1].name == "Empty" && _allRoots[_allRoots.Count - 5].name != "TurnRight(Clone)" &&
                _allRoots[_allRoots.Count - 1].name != "SplitLeft(Clone)" && _allRoots[_allRoots.Count - 5].name != "TurnLeft(Clone)" &&
                _allRoots[_allRoots.Count - 5].name != "SplitOut(Clone)" && _allRoots[_allRoots.Count - 2].name != "SplitLeft(Clone)" &&
                _allRoots[_allRoots.Count - 5].name != "SplitRight(Clone)" && _allRoots[_allRoots.Count - 2].name != "TurnLeft(Clone)")
            {
                keys.Add("SplitRight");
            }

            if (_allRoots[_allRoots.Count - 1].name != "FuseLeft(Clone)" &&
            (_allRoots[_allRoots.Count - 4].name == "Straight(Clone)" || (_allRoots[_allRoots.Count - 4].name == "StraightCurved(Clone)") ||
            (_allRoots[_allRoots.Count - 4].name == "SplitLeft(Clone)")) &&
            (_allRoots[_allRoots.Count - 6].name == "Straight(Clone)" || (_allRoots[_allRoots.Count - 6].name == "StraightCurved(Clone)") ||
            (_allRoots[_allRoots.Count - 6].name == "SplitRight(Clone)")) && z != (_width * 3.5) - 3.5f && z != 0 &&
            _allRoots[_allRoots.Count - 1].name == "Empty" && _allRoots[_allRoots.Count - 5].name == "Empty" &&
            _allRoots[_allRoots.Count - 2].name != "FuseRight(Clone)")
            {
                keys.Add("FuseIn");
            }
        }

        if (keys.Count == 0)
        {
            _canSpawn = false;
        }
        else
        {
            _canSpawn = true;
        }

        #endregion

        List<int> w = new List<int>();

        foreach (string k in keys)
        {
            w.Add(weightTable[k]);
        }
        int[] weights = w.ToArray();
        int randomWeight = Random.Range(0, weights.Sum());
        int accumulation = 0;
        int[] runningTotal = new int[weights.Length];

        for (int i = 0; i < weights.Length; i++)
        {
            accumulation += weights[i];
            runningTotal[i] = accumulation;
        }

        var low = 0;
        var high = weights.Length;

        while (low < high)
        {
            var mid = (int)((low + high) / 2);
            var distance = runningTotal[mid];

            if (distance < randomWeight)
            {
                low = mid + 1;
            }
            else if (distance > randomWeight)
            {
                high = mid;
            }
            else
            {
                return mid;
            }
        }
        return low;
    }
}
