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

public class LevelGeneratorV2 : MonoBehaviour
{
    public LineRenderer debugLine;
    [SerializeField]public Range amplitude = new Range(1,2);
    [SerializeField]public Range distance = new Range(2,5);
    [SerializeField]public Range[] heights;

    public float frequency = 0.1f;

    [Header("Generation")]
    public SpriteShapeController[] shapes;

    List<SpriteShapeController> pooled,borrowed = new List<SpriteShapeController>();
    public float tangentSmoothness = 1.5f;

    float space =0;

    [Header("Asteroids")]
    public float asteroidGenerationHeightThreshold =6;
    public GameObject[] asteroidPrefabs;
    public Range asteroidScale = new Range(1,5);
    public Range asteroidSpeed = new Range(0.1f,0.5f);
    public Range asteroidTorque = new Range(0.1f,0.5f);
    public Range asteroidsPerBlock = new Range(4,8);


    // Start is called before the first frame update
    void Start()
    {
        Application.targetFrameRate = 60;
        // #if UNITY_EDITOR
        //     debugLine.gameObject.SetActive(true);
        // #else
        //     debugLine.gameObject.SetActive(false);
        // #endif
        pooled = new List<SpriteShapeController>();
        borrowed = new List<SpriteShapeController>();
        foreach(SpriteShapeController shape in shapes){pooled.Add(shape);}
        GenerateNext();
    }

    // Update is called once per frame
    void Update()
    {
        if(PlayerController.position.x > lastStart + 50){
            GenerateNext();
            Debug.Log("Generating Next");
        }
    }

    float lastStart;
    List<Vector3> points = new List<Vector3>();
    float a;
    public float heightSmoothness = 0.1f;
    void GenerateNext(int amount = 50){
        Range height = heights[Random.Range(0,heights.Length)];
        Debug.Log(height);
        if(space <= 0){space = height.GetRandom();}

        space = Mathf.Lerp(space, height.GetRandom(), heightSmoothness);
        if(points.Count <= 0){points.Add(new Vector3(0,0));}
        int startIndex = points.Count-1;
        lastStart = points[startIndex].x;

        int asteroids = 1;
        int asteroidsLimit = (int)asteroidsPerBlock.GetRandom();
        for(int i=0; i < amount; i++){
            a+= frequency;
            float y = Mathf.Sin(a) * amplitude.GetRandom();
            float x = points[points.Count-1].x + distance.GetRandom();

            points.Add(new Vector3(x,y));

            if(asteroids < Mathf.CeilToInt(i / (amount/(float)asteroidsLimit)) && height.max > asteroidGenerationHeightThreshold){
                // Rigidbody2D rb = Instantiate(asteroidPrefabs[Random.Range(0,asteroidPrefabs.Length)], new Vector3(x,y),Quaternion.identity).GetComponent<Rigidbody2D>();
                Rigidbody2D rb = ObjectPool.Spawn(asteroidPrefabs[Random.Range(0,asteroidPrefabs.Length)], new Vector3(x,y)).GetComponent<Rigidbody2D>();
                borrowedAsteroids.Add(rb.gameObject);
                rb.AddForce(new Vector2(asteroidSpeed.GetRandom(), asteroidSpeed.GetRandom()));
                rb.AddTorque(asteroidTorque.GetRandom());
                rb.transform.localScale = rb.transform.localScale * asteroidScale.GetRandom();
                asteroids++;
            }
        }


        CleanupBorrowed();

        //Bottom Terrain
        SpriteShapeController bot_controller = pooled[0];
        borrowed.Add(pooled[0]);
        pooled.RemoveAt(0);

        bot_controller.spline.Clear();
        InsertNewPoint(bot_controller, points[startIndex]- new Vector3(0, 50));
        for(int i=startIndex; i < points.Count; i++){
            InsertNewPoint(bot_controller, points[i] - new Vector3(0, space));
        }
        InsertNewPoint(bot_controller, points[points.Count-1] - new Vector3(0,50));
        bot_controller.GetComponent<PolygonCollider2D>().enabled=true;
        bot_controller.transform.position = Vector3.zero;
        bot_controller.gameObject.SetActive(false);
        bot_controller.gameObject.SetActive(true);

        //Top Terrain
        SpriteShapeController top_controller = pooled[0];

        borrowed.Add(pooled[0]);
        pooled.RemoveAt(0);

        top_controller.spline.Clear();
        InsertNewPoint(top_controller, points[startIndex]+ new Vector3(0, 50));
        for(int i=startIndex; i < points.Count; i++){
            InsertNewPoint(top_controller, points[i] + new Vector3(0, space));
        }
        InsertNewPoint(top_controller, points[points.Count-1] + new Vector3(0,50));
        top_controller.GetComponent<PolygonCollider2D>().enabled=true;
        top_controller.transform.position = Vector3.zero;
        top_controller.gameObject.SetActive(false);
        top_controller.gameObject.SetActive(true);

        UpdateLine();
    }

    public List<GameObject> borrowedAsteroids = new List<GameObject>();
    void CleanupBorrowed(){
        for(int i= borrowed.Count-1; i > 0; i--){
            if(borrowed[i].spline.GetPosition(borrowed[i].spline.GetPointCount()-1).x < PlayerController.position.x -30){
                pooled.Add(borrowed[i]);
                borrowed[i].GetComponent<PolygonCollider2D>().enabled = false;
                borrowed.RemoveAt(i);
            }
        }
        for(int i=borrowedAsteroids.Count-1; i> 0; i--){
            if(borrowedAsteroids[i].transform.position.x + 20 < PlayerController.position.x){
                ObjectPool.Despawn(borrowedAsteroids[i]);
                borrowedAsteroids.RemoveAt(i);
            }
        }
    }

    void UpdateLine(){
        debugLine.positionCount = points.Count;
        debugLine.SetPositions(points.ToArray());
    }

    void InsertNewPoint(SpriteShapeController spriteShapeController,Vector3 point){
        int index= spriteShapeController.spline.GetPointCount();
        spriteShapeController.spline.InsertPointAt(index, point);
        spriteShapeController.spline.SetTangentMode(index, ShapeTangentMode.Continuous);
        spriteShapeController.spline.SetLeftTangent(index, new Vector3(-tangentSmoothness,0));
        spriteShapeController.spline.SetRightTangent(index,new Vector3(tangentSmoothness,0));
    }
}
