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

/// <summary>
/// менеджер тайлов
/// инициализация, создание новых, удаление, отслеживание кол-ва тайлов
/// </ summary >
public class TileManagerScript : MonoBehaviour
{
    /// <summary>
    /// to do
    /// </summary>
    [HideInInspector]
    public ScoreManagerScript scoreManager;

    /// <summary>
    /// число тайлов, которые будут созданы 
    /// </summary>
    [SerializeField]
    private int _NumTile;

    /// <summary>
    /// расстояние между центрами двух тайлов, нужно переделать, чтобы бралось само
    /// </summary>
    [SerializeField]
    private float _DistanceTiles;
    public float DistanceTiles
    {
        get => _DistanceTiles;
        set => _DistanceTiles = value;
    }

    /// <summary>
    /// список префабов для случайной генерации
    /// </summary>
    [SerializeField]
    private List<GameObject> _TilePrefs = new List<GameObject>();

    /// <summary>
    /// поле массива тайлов
    /// </summary> 
    [SerializeField]
    private List<GameObject> _Tiles = new List<GameObject>();

    /// <summary>
    /// счётчик кол-ва созданных тайлов
    /// </summary>
    private int _CountTile = 0;

    [SerializeField]
    private GameObject _PlayerSetup;

    /// <summary>
    /// при запуске сцены, создание новых тайлов
    /// </summary>
    private void Start()
    {

        // координата самого дальнего тайла
        float z = -(_NumTile / 2) * _DistanceTiles;

        // создание тайлов назад от игрока, где i номер тайла, а z координата transfrom.position.z 
        for (int i = 0; i < _NumTile; i++)
        {
            // генерация нового тайла, с собственным z
            GameObject tile = GenerateTile(new Vector3(0, 0, z), new Quaternion(0, 0, 0, 0));

            if (z < 0)
            {
                SetCloseZone(tile);
                SetTrigZone(tile);
            }
            if(z == 0)
            {
                SetTrigZone(tile);
            }

            // увелечение позиции тайла по transform.position.z
            z += _DistanceTiles;
        }



        //_PlayerSetup.SetActive(true);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="tile"></param>
    private void SetTrigZone(GameObject tile)
    {
        // цикл нахождения скрипта тригера по тегу
        foreach (Transform child in tile.transform)
        {
            // если найден тег, то передать и закрыть
            if (child.CompareTag("Trigger Zone"))
            {
                // получение адреса объекта
                child.GetComponent<TriggerZoneScript>().WasTrigged = true;

                // выход из цикла
                break;
            }
        }
    }

    /// <summary>
    /// Активация зоны закрытия
    /// </summary>
    /// <param name="tile"></param>
    private void SetCloseZone(GameObject tile)
    {
        foreach (Transform child in tile.transform)
        {
            // если найден тег, то передать и закрыть
            if (child.CompareTag("Close Zone"))
            {
                // передача адреса объекта
                child.gameObject.SetActive(true);

                // выход из цикла
                break;
            }
        }
    }

    /// <summary>
    /// присваивание тайлу его номера в имя
    /// </summary>
    /// <param name="tile">передаваемый тайл</param>
    private void NewNameTile(GameObject tile)
    {
        // увеличение счётчика тайлов
        _CountTile++;

        // Прибавить к имени тайла его номер
        tile.name += _CountTile;
    }

    /// <summary>
    /// генератор тайлов по заданному transform
    /// </summary>
    /// <param name="pos">позиция нового тайла</param>
    /// <param name="rot">поворот нового тайла</param>
    /// <returns>возвращает созданный тайл</returns>
    public GameObject GenerateTile(Vector3 pos, Quaternion rot)
    {
        // создание нового тайла
        GameObject newTile = Instantiate(GetRandomObject(_TilePrefs), pos, rot);

        // присваивание номера
        NewNameTile(newTile);

        GameObject prevTile = _Tiles.LastOrDefault();

        TransCloseZoneSub(newTile, prevTile);

        // добавление массива в отслеживание
        _Tiles.Add(newTile);

        // подпись нового тайла на эвент
        SubTileTrigEvent(newTile);

        // перемещение нового тайла в менеджер как child
        newTile.transform.SetParent(gameObject.transform);

        //Debug.Log($"Was created new tile awake");

        return newTile;
    }

    /// <summary>
    /// генерация тайла с добавлением его в конец списка
    /// </summary>
    /// <returns>возвращает созданный тайл</returns>
    public GameObject GenerateTile()
    {
        // индекс последнего элемента
        int index = _NumTile - 1;

        // позиция и поворот последнего тайла
        Vector3 pos = _Tiles[index].transform.position;
        Quaternion rot = _Tiles[index].transform.rotation;

        // создание нового position для генерации нового тайла
        Vector3 newVector = new Vector3(pos.x, pos.y, pos.z + _DistanceTiles);

        // создание нового тайла и получение его адреса
        GameObject newTile = Instantiate(GetRandomObject(_TilePrefs), newVector, rot);

        // присваивание номера
        NewNameTile(newTile);

        GameObject prevTile = _Tiles.LastOrDefault();

        TransCloseZoneSub(newTile, prevTile);

        // добавление массива в отслеживание
        _Tiles.Add(newTile);

        // перемещение нового тайла в менеджер как child
        newTile.transform.SetParent(gameObject.transform);

        // подпись нового тайла на эвент тригера зоны
        SubTileTrigEvent(newTile);

        // удаление первого в списке тайла
        DeleteTile();

        //Debug.Log($"Was created new tile");

        return newTile;
    }

    /// <summary>
    /// Удалитель тайлов
    /// </summary>
    public void DeleteTile()
    {
        // индекс первого тайла в списке
        int index = 0;

        // удаление GameObject первого тайла
        Destroy(_Tiles[index]);

        // удаление первого тайла в списке
        _Tiles.RemoveAt(index);

        //Debug.Log("Was deleted tile");
    }

    private delegate void SubTileTrigDelegate();
    private SubTileTrigDelegate _SubTileTrigEvent;

    /// <summary>
    /// Подпись на триггер эвент в тайле
    /// </summary>
    /// <param name="tile">передаваемый тайл на подпись</param>
    private void SubTileTrigEvent(GameObject tile)
    {
        // прохождение по всем child в tile
        foreach (Transform child in tile.transform)
        {
            // если тайл является тригерной зоной, то подписаться и закончить
            if (child.CompareTag("Trigger Zone"))
            {
                // в подпись передаётся анонимная функция, так как GenerateTile() возвращает GameObject
                child.GetComponent<TriggerZoneScript>().TriggerZoneEvent.AddListener(() => GenerateTile());

                // в подпись передаётся функция увелечения счёта
                child.GetComponent<TriggerZoneScript>().TriggerZoneEvent.AddListener(scoreManager.Increase);

                // в подпись передаётся функция перемещения счёта
                child.GetComponent<TriggerZoneScript>().TriggerZoneEvent.AddListener(scoreManager.UpdatePos);

                // выход из цикла
                break;
            }
        }
    }

    /// <summary>
    /// Передача в ново созданный тайл, зоны закртытия предыдущего
    /// </summary>
    /// <param name="newTile">Новый тайл</param>
    /// <param name="pervTile">Предыдущий тайл</param>
    public void TransCloseZoneSub(GameObject newTile, GameObject pervTile)
    {
        // Получение зоны закрытия
        GameObject closeZone = null;

        // скрипт с эвентом тригера
        TriggerZoneScript triggerZoneScript = null;

        // проверка наличия нового тайла
        if (newTile != null)
        {
            // цикл нахождения скрипта тригера по тегу
            foreach (Transform child in newTile.transform)
            {
                // если найден тег, то передать и закрыть
                if (child.CompareTag("Trigger Zone"))
                {
                    // получение адреса объекта
                    triggerZoneScript = child.GetComponent<TriggerZoneScript>();

                    // выход из цикла
                    break;
                }
            }
        }
        // проверка на наличие предыдущего тайла
        if (pervTile != null)
        {
            // поиск зоны закрытия по тегу
            foreach (Transform child in pervTile.transform)
            {
                // если найден тег, то передать и закрыть
                if (child.CompareTag("Close Zone"))
                {
                    // передача адреса объекта
                    closeZone = child.gameObject;

                    // выход из цикла
                    break;
                }
            }
        }
        // проверка на первосозданный тайл, у него нет предыдущего тайла, поэтому нечего закрывать
        if (closeZone != null)
        {
            // передача анонимной функции активации зоны закрытия
            triggerZoneScript.GetComponent<TriggerZoneScript>().TriggerZoneEvent.AddListener(() => closeZone.SetActive(true));
        }
    }

    /// <summary>
    /// Генератор случайно взятого объекта
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">Список из которого брать</param>
    /// <returns></returns>
    T GetRandomObject<T>(List<T> list)
    {
        // проверка на пустоту списка
        if (list == null || list.Count == 0)
        {
            return default;
        }

        // Генерация случайного индекса
        int randomIndex = UnityEngine.Random.Range(0, list.Count);
        return list[randomIndex];
    }
}
