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

public enum GameView
{
    DroneCreation,
    WarpSelection,
    DroneControl
}

public struct WorldConfigPair
{
    public WorldGenConfig config;
    public World world;
}

public class Game : MonoBehaviour {

    public static Game instance;

    public Tileset[] tilesets;
    public WorldGenConfig[] configurations;

    public int droneSpawnWorldIndex;
    public int[] validDroneSpawnTiles;

    public GameObject dronePrefab;
    public List<DroneController> drones;

    public WorldConfigPair[] worlds;

    public GameView currentView;

    public GameObject mainCamera;

    public GameObject gridPrefab;

    private void Awake()
    {
        instance = this;
        drones = new List<DroneController>();
        worlds = new WorldConfigPair[configurations.Length];
        for (int i=0; i<configurations.Length; i++)
        {
            worlds[i].config = configurations[i];
        }
        World.onWorldChange += OnWorldSelect;
    }

    private void Update()
    {
        if (currentView == GameView.DroneControl)
            Time.timeScale = 1;
        else
            Time.timeScale = 0;

        foreach (var world in worlds)
        {
            if (world.world == null)
                continue;
            for (int i=0; i<world.world.indexCount; ++i)
            {
                world.world.blocked[i] &= ~World.BlockMask.Drone;
            }
        }
        var indicesCovered = new HashSet<int>();
        foreach (var drone in drones)
        {
            var world = drone.world;
            indicesCovered.Clear();
            var dronePos = drone.transform.position;
            indicesCovered.Add(world.GetIndex(Mathf.FloorToInt(dronePos.x), Mathf.FloorToInt(dronePos.z)));
            indicesCovered.Add(world.GetIndex(Mathf.CeilToInt(dronePos.x), Mathf.FloorToInt(dronePos.z)));
            indicesCovered.Add(world.GetIndex(Mathf.FloorToInt(dronePos.x), Mathf.CeilToInt(dronePos.z)));
            indicesCovered.Add(world.GetIndex(Mathf.CeilToInt(dronePos.x), Mathf.CeilToInt(dronePos.z)));
            
            foreach (int i in indicesCovered)
            {
                if (world.IsValid(i))
                    world.blocked[i] |= World.BlockMask.Drone;
            }
        }
    }

    public void OnDroneSelect(DroneController prevDrone, DroneController currentDrone)
    {
        this.currentView = GameView.DroneControl;
        var worldIndex = World.GetWorldIndex(currentDrone.transform.position);
        World.currentWorldIndex = worldIndex;
        mainCamera.GetComponent<Camera>().enabled = currentDrone.camClass != CameraClass.Single;
        currentDrone.GetComponentInChildren<Camera>().enabled = currentDrone.camClass == CameraClass.Single;
        
        mainCamera.transform.SetParent(currentDrone.transform);
        mainCamera.transform.localPosition = new Vector3(-World.currentInstance.height / 2, 14, -World.currentInstance.height);
    }

    public World GetDronePlacementWorld()
    {
        return GetWorld(droneSpawnWorldIndex);
    }

    public int GetDronePlacementTile()
    {
        var spawnWorld = GetDronePlacementWorld();
        foreach (var t in validDroneSpawnTiles)
        {
            if ((spawnWorld.blocked[t] & World.BlockMask.Drone) != 0)
                continue;
            return t;
        }
        return -1;
    }

    public void RegisterDrone(DroneController newDrone)
    {

        drones.Add(newDrone);
    }

    public void OnWorldSelect(int previous, int current)
    {
        if (previous >= 0 && worlds.Length > previous)
            worlds[previous].world.gameObject.SetActive(false);

        var w = GetWorld(current);
        if (w != null)
            worlds[current].world.gameObject.SetActive(true);
    }

    public World GetWorld(int index)
    {
        if (index < 0 || index >= worlds.Length)
            return null;
        if (worlds[index].world == null)
        {
            worlds[index].world = World.Create(index);
            worlds[index].world.Gen();
        }
        return worlds[index].world;
    }

    public void NewDroneMode()
    {
        this.currentView = GameView.DroneCreation;
    }
}
