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

public class InfiniteMovingBelt : MonoBehaviour
{
    public GameObject item;
    public float speed = -1f;
    public float spawnOffsetFromScreen = 1f;
    public float destroyOffsetFromScreen = 1f;
    public float spawnDistance = 5f;
    public float spawnProbability = 1f;

    private readonly List<GameObject> instances = new List<GameObject>();

    void Start()
    {
        // Create the instance
        MakeInitialSpawning();
    }

    void Update()
    {

        foreach(GameObject instance in instances.ToArray())
        {
            if (CanDestroy(instance))
            {
                Destroy(instance);
                instances.Remove(instance);
                continue;
            }

            Vector3 originalPos = instance.transform.position;

            float posX = originalPos.x + (speed * Time.deltaTime);
            Vector3 newPosition = new Vector3(posX, originalPos.y, originalPos.z);

            instance.transform.position = newPosition;
        }

        SpawnIfNeeded();
    }

    private Vector3 GetScreenSize()
    {
        var screenSizePixels = new Vector3(Screen.width, Screen.height, 0);
        return Camera.main.ScreenToWorldPoint(screenSizePixels);
    }

    private bool CanDestroy(GameObject i)
    {
        Vector3 screenSize = GetScreenSize();
        return i.transform.position.x < GetDestroyX();
    }

    private void SpawnIfNeeded()
    {
        GameObject last = instances[instances.Count - 1];
        float diff = GetSpawnX() - last.transform.position.x;

        if (diff >= spawnDistance)
        {
            SpawnWithProbability(GetDefaultStartPos());
        }
    }

    private float GetSpawnX()
    {
        return GetScreenSize().x + spawnOffsetFromScreen;
    }

    private float GetDestroyX()
    {
        return -(GetScreenSize().x + destroyOffsetFromScreen);
    }

    private GameObject SpawnWithProbability(Vector3 startPos)
    {
        bool canSpawn = Random.Range(0f, 1f) < spawnProbability;
        if (canSpawn)
        {
            return SpawnItem(startPos);
        }

        return SpawnItemAndHide(startPos);
    }

    private GameObject SpawnItem(Vector3 startPos, bool addToFront = false)
    {
        GameObject instance = Instantiate<GameObject>(item, startPos, Quaternion.identity);

        if (addToFront)
        {
            instances.Insert(0, instance);
        } else
        {
            instances.Add(instance);
        }

        return instance;
    }

    private GameObject SpawnItemAndHide(Vector3 startPos)
    {
        startPos.y = 10;
        GameObject instance = Instantiate<GameObject>(item, startPos, Quaternion.identity);
        instances.Add(instance);

        return instance;
    }

    private Vector3 GetDefaultStartPos()
    {
        return new Vector3(
            GetSpawnX(),
            gameObject.transform.position.y,
            gameObject.transform.position.z
        );
    }

    private void MakeInitialSpawning()
    {
        Vector3 startPos = GetDefaultStartPos();
        while(startPos.x > GetDestroyX())
        {
            SpawnItem(startPos, addToFront:true);
            startPos.x -= spawnDistance;
        }
    }
}