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


public delegate void GenerationCompleteCallback();

public class WorldGenerator : MonoBehaviour
{

    public GameObject patchPrefab;
    public GameObject holePrefab;

    public DifficultySetting currSetting;
    public bool generateOnStart = false;
    public event GenerationCompleteCallback GenerationCompleteHandler;

    [HideInInspector]
    public List<GameObject> _spawnPatchs = new List<GameObject>();
    [HideInInspector]
    public List<GameObject> _spawnHoles  = new List<GameObject>();

    // Start is called before the first frame update
    void Start()
    {
        if (generateOnStart) Generate(currSetting);
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void Generate(DifficultySetting setting)
    {
        Debug.Log("Generating World");
        SpawnPatches(setting);
        SpawnHoles(setting);
        CullNearbyPatchesFromHoles(setting);
        if (GenerationCompleteHandler != null) GenerationCompleteHandler();
    }

    void SpawnPatches(DifficultySetting setting)
    {
        int count = 0;
        Debug.Log("Spawning Patches");
        PoissonDiscSampler sampler      = new PoissonDiscSampler (setting.worldWidth, 
                                                                 setting.worldHeight, 
                                                   setting.patchRadiusFromEachOther);

        Vector2 offset = new Vector2(setting.worldWidth/2,setting.worldHeight/2);
        foreach (Vector2 sample in sampler.Samples()) 
        {
            GameObject newPatch  =  Instantiate(patchPrefab);
            newPatch.transform.position = transform.position + 
                                           (Vector3)(sample) - 
                                           (Vector3)(offset);
            newPatch.name = "Patch " + count.ToString();
            count++;

            newPatch.transform.Rotate(0,0,Random.Range(0,360));
            newPatch.transform.parent = transform;
            _spawnPatchs.Add(newPatch);
        }
        Debug.Log("<color=green> " + _spawnPatchs.Count + 
                  " has been generated </green>");
    }

    void SpawnHoles(DifficultySetting setting)
    {
        Debug.Log("Spawning Holes");
        PoissonDiscSampler sampler      = new PoissonDiscSampler(setting.worldWidth,
                                                                 setting.worldHeight,
                                                                 setting.holeDistanceFromEachOther);

        Vector2 offset = new Vector2(setting.worldWidth/2,setting.worldHeight/2);

        int count = 0;
        foreach (Vector2 sample in sampler.Samples())
        {
            GameObject newHole = Instantiate(holePrefab);
            newHole.transform.position = transform.position + 
                                        (Vector3)(sample) - 
                                        (Vector3)(offset);
            newHole.transform.position *= setting.holeBleedFromWorldBound;
            HoleBehaviour holeComp = newHole.GetComponent<HoleBehaviour>();
            _spawnHoles.Add(newHole);
            count++;
            if (count >= setting.numHoles.Count) break;
        }
    }

    void CullNearbyPatchesFromHoles(DifficultySetting setting)
    {
        Debug.Log("Culling Patches that are too near");
        foreach(GameObject patch in _spawnPatchs)
        {
            foreach (GameObject hole in _spawnHoles)
            {
                Vector3 dist = patch.transform.position - hole.transform.position;
                float sqMag = dist.sqrMagnitude;
                if (sqMag < setting.patchFromHoleAllowance * setting.patchFromHoleAllowance)
                {
                    Debug.Log("<color=red> Culling hole that is too near </color>");
                    Destroy(patch);
                }
            }
        }
    }


}
