using GadgetCore.API;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using Random = System.Random;

namespace Subworlds
{
  public class MeteroidGenerator
  {
    private static readonly FieldInfo chunksField = typeof(SpawnerScript).GetField("chunks", BindingFlags.NonPublic | BindingFlags.Instance);
    private static readonly Material materialaBackLight = new Material(Shader.Find("Unlit/Transparent")) { mainTexture = GadgetCoreAPI.LoadTexture2D("Meteoroid/parallax.png") };

    private static readonly Material materialaParalexStars = new Material(Shader.Find("Unlit/Transparent")) { mainTexture = GadgetCoreAPI.LoadTexture2D("Meteoroid/bgStars.png") };
    private static readonly Material materialaParalexNone = new Material(Shader.Find("Unlit/Transparent")) { mainTexture = GadgetCoreAPI.LoadTexture2D("Meteoroid/bgNone.png") };

    public static readonly FieldInfo networkStuffField = typeof(Chunk).GetField("networkStuff", BindingFlags.NonPublic | BindingFlags.Instance);
    public static readonly FieldInfo tempField = typeof(Chunk).GetField("temp", BindingFlags.NonPublic | BindingFlags.Instance);

    private static int W = 32; //128 + 64;
    private static int H = 32; //128 - 32;

    private static float GetSizeForPixels(int px)
    {
      return 1f / 16f * px;
    }

    private static void MarkGeneration(int x, int y, int[][] arr)
    {
      if (x >= 0 && x < W && y >= 0 && y < H)
        arr[x][y] = 1;
    }

    private static bool CheckGeneration(int x, int y, int[][] arr)
    {
      if (x >= 0 && x < W && y >= 0 && y < H)
        if (arr[x][y] == 0)
          return true;
        else return false;
      return true;
    }
    public static void GenarateTown(SpawnerScript s, int[] param)
    {
      GameScript.isTown = true;
      if (GameScript.districtLevel % 2 != 0)
      {
        GameScript.districtLevel++;
      }

      s.backLights.SetActive(true);
      s.mainLight.SetActive(false);
      s.backLights.GetComponent<Renderer>().material = materialaBackLight;
      //s.mainLight.GetComponentInChildren<Light>().color = new Color(0.05f, 0.05f, 0.05f, 0.1f);

      s.bg[0].GetComponent<Renderer>().material = materialaParalexStars;
      s.bg[1].GetComponent<Renderer>().material = materialaParalexNone;
      s.bg[2].GetComponent<Renderer>().material = materialaParalexNone;
      s.bg[3].GetComponent<Renderer>().material = materialaParalexNone;

      var chunks = (GameObject[])chunksField.GetValue(s);
      var num = 0;

      chunks[num] = (GameObject)UnityEngine.Object.Instantiate(Resources.Load("z/Subworlds/MeteorBase"), new Vector3((float)(218 + 0 * 128 + 4 * 8), 0f, 5f), Quaternion.Euler(0f, 180f, 180f));
      num++;

      if (Network.isServer)
      {
        chunks[num] = new GameObject("chunk");
        var chunk = chunks[num].AddComponent<Chunk>();
        PopulateTown(chunk);
        num++;
      }
    }

    public static void Genarate(SpawnerScript s, int[] param)
    {
      GameScript.isTown = false;

      s.backLights.SetActive(true);
      s.mainLight.SetActive(false);
      s.backLights.GetComponent<Renderer>().material = materialaBackLight;

      s.bg[0].GetComponent<Renderer>().material = materialaParalexStars;
      s.bg[1].GetComponent<Renderer>().material = materialaParalexNone;
      s.bg[2].GetComponent<Renderer>().material = materialaParalexNone;
      s.bg[3].GetComponent<Renderer>().material = materialaParalexNone;

      //s.backLights.SetActive(true);
      s.mainLight.SetActive(true);
      s.mainLight.GetComponentInChildren<Light>().color = new Color(1f, 1f, 1f, 1f);

      var chunks = (GameObject[])chunksField.GetValue(s);
      var num = 0;
      try
      {
        if (Network.isServer)
        {
          chunks[num] = new GameObject("chunk");
          var chunk = chunks[num].AddComponent<Chunk>();
          PopulateWorld(chunk);
          num++;
        }
      }
      catch (System.Exception e) { Core.logger.LogConsole(e); }
    }

    private static List<int[]> spawnLocations = new List<int[]>();
    private static System.Random random = new System.Random();
    public static void PopulateTown(Chunk chunk)
    {
      var networkStuff = new GameObject[400];
      networkStuffField.SetValue(chunk, networkStuff);

      try
      {

        int temp = (int)tempField.GetValue(chunk);

        networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("npcStorage"), new Vector3(248f - 4 * 1, -6.118f, 0.3f), Quaternion.identity, 0);
        temp++;
        networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("npc2103"), new Vector3(248f + 4 * 0, -6.118f, 0.3f), Quaternion.identity, 0);
        temp++;
        networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("npc/npcQuest"), new Vector3(248f + 4 * 2, -6.118f, 0.3f), Quaternion.identity, 0);
        temp++;
      }
      catch (System.Exception e) { Core.logger.LogError(e); }

      GameScript.endPortal[0] = (GameObject)Network.Instantiate((GameObject)Resources.Load("portal"), new Vector3(248f + 4 * 4, -6.118f, 0f), Quaternion.identity, 0);
      GameScript.endPortalUA[0] = GameScript.endPortal[0].transform.GetChild(0).gameObject;
      GameScript.endPortal[0].GetComponent<NetworkView>().RPC("Activate", RPCMode.All, new object[0]);
      GameScript.endPortalUA[0].GetComponent<NetworkView>().RPC("Set", RPCMode.AllBuffered, new object[] { Core.lastBiome == -1 ? Core.meteroidPlanet.GetID() : Core.lastBiome, 0, 0 });

      GameScript.endPortal[3] = (GameObject)Network.Instantiate((GameObject)Resources.Load("portal"), new Vector3(248f - 4 * 3, -6.118f, 0f), Quaternion.identity, 0);
      GameScript.endPortalUA[3] = GameScript.endPortal[3].transform.GetChild(0).gameObject;
      GameScript.endPortal[3].GetComponent<NetworkView>().RPC("Activate", RPCMode.All, new object[0]);
      GameScript.endPortalUA[3].GetComponent<NetworkView>().RPC("Set", RPCMode.AllBuffered, new object[] { 98, 0, 3 });
    }

    public static void PopulateWorld(Chunk chunk)
    {
      var networkStuff = new GameObject[400];
      networkStuffField.SetValue(chunk, networkStuff);

      int temp = (int)tempField.GetValue(chunk);

      int[][] genSpots = new int[W][];
      for (int i = 0; i < W; i++)
        genSpots[i] = new int[H];

      {
        int x = 15;
        int y = 10;
        for (int xOff = -2; xOff < 3; xOff++)
          for (int yOff = -2; yOff < 6; yOff++)
            MarkGeneration(x + xOff, y + yOff, genSpots);
        networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("z/Subworlds/BaseBlockNormal"), new Vector3(242 + 4 * x - 60, y * 4 - 60, 5), Quaternion.identity, 0);
        temp++;
      }
      {
        int porterGenerated = 0;
        int overflow = 0;
        int x = random.Next(W / 2) + W / 2;
        int y = random.Next(H / 2) + H / 2;

        bool addLoopPortal = false;
        foreach (var gadget in GadgetCore.API.Gadgets.ListAllEnabledGadgets())
          if (gadget.Info?.ModName == "Loop Portal")
          {
            addLoopPortal = true;
            break;
          }

        while (overflow < 1000 && porterGenerated < 1)
        {
          overflow++;
          bool noGen = false;
          for (int xOff = -1; xOff < 2; xOff++)
            for (int yOff = -1; yOff < 4; yOff++)
              if (!CheckGeneration(x + xOff, y + yOff, genSpots))
                noGen = true;
          if (!noGen)
          {
            for (int xOff = -1; xOff < 2; xOff++)
              for (int yOff = -1; yOff < 4; yOff++)
                MarkGeneration(x + xOff, y + yOff, genSpots);
            networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("z/Subworlds/BaseBlockNormal"), new Vector3(242 + 4 * x - 60, y * 4 - 60, 5), Quaternion.identity, 0);
            temp++;
            GameScript.endPortal[porterGenerated] = (GameObject)Network.Instantiate((GameObject)Resources.Load("portal"), new Vector3(242 + x * 4 - 60, y * 4 - 60 + GetSizeForPixels(54) + 1.451f + 1, 0f), Quaternion.identity, 0);
            GameScript.endPortalUA[porterGenerated] = GameScript.endPortal[porterGenerated].transform.GetChild(0).gameObject;
            GameScript.endPortal[porterGenerated].GetComponent<NetworkView>().RPC("Activate", RPCMode.All, new object[0]);
            GameScript.endPortalUA[porterGenerated].GetComponent<NetworkView>().RPC("Set", RPCMode.AllBuffered, new object[] { SpawnerScript.curBiome, 0, porterGenerated });
            porterGenerated++;
          }
          x = Mathf.Min(x + random.Next(5) - 2, W);
          y = Mathf.Min(y + random.Next(5) - 2, H);
        }
        //while (addLoopPortal && overflow < 5000)
        //{
        //  overflow++;
        //  bool noGen = false;
        //  for (int xOff = -1; xOff < 2; xOff++)
        //    for (int yOff = -1; yOff < 4; yOff++)
        //      if (!CheckGeneration(x + xOff, y + yOff, genSpots))
        //        noGen = true;
        //  if (!noGen)
        //  {
        //    for (int xOff = -1; xOff < 2; xOff++)
        //      for (int yOff = -1; yOff < 4; yOff++)
        //        MarkGeneration(x + xOff, y + yOff, genSpots);
        //    networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("z/Subworlds/BaseBlockNormal"), new Vector3(242 + 4 * x - 60, y * 4 - 60, 5), Quaternion.identity, 0);
        //    temp++;
        //    var i = (GameObject)Network.Instantiate((GameObject)Resources.Load("portal"), new Vector3(242 + x * 4 - 60, y * 4 - 60 + GetSizeForPixels(54) + 1.451f + 1, 0f), Quaternion.identity, 0);
        //    var iUA = i.transform.GetChild(0).gameObject;
        //    i.GetComponent<NetworkView>().RPC("Activate", RPCMode.All, new object[0]);
        //    iUA.GetComponent<NetworkView>().RPC("Set", RPCMode.AllBuffered, new object[] { SpawnerScript.curBiome, 0, 4 });
        //    i.transform.parent = GameScript.endPortal[0].transform;
        //    networkStuff[temp] = i;
        //    temp++;
        //    break;
        //  }
        //  x = Mathf.Min(x + random.Next(5) - 2, W);
        //  y = Mathf.Min(y + random.Next(5) - 2, H);
        //}
      }
      {
        int r = 0;
        int overflow = 0;

        while (overflow < 15000 && r < 700)
        {
          overflow++;
          int i = random.Next(6);
          int x = random.Next(W);
          int y = random.Next(H);

          bool noGen = false;
          switch (i)
          {
            case 0:
            case 1:
            case 2:
              for (int xOff = -1; xOff < 2; xOff++)
                for (int yOff = -1; yOff < 2; yOff++)
                  if (!CheckGeneration(x + xOff, y + yOff, genSpots))
                    noGen = true;
              break;
            case 3:
            case 4:
              for (int xOff = -1; xOff < 2; xOff++)
                for (int yOff = -1; yOff < 2; yOff++)
                  if (!CheckGeneration(x + xOff, y + yOff, genSpots))
                    noGen = true;
              break;
            case 5:
              for (int xOff = -2; xOff < 3; xOff++)
                for (int yOff = -2; yOff < 3; yOff++)
                  if (!CheckGeneration(x + xOff, y + yOff, genSpots))
                    noGen = true;
              break;
          }
          if (!noGen)
          {
            r++;
            switch (i)
            {
              case 0:
              case 1:
              case 2:
                for (int xOff = -1; xOff < 2; xOff++)
                  for (int yOff = -1; yOff < 2; yOff++)
                    MarkGeneration(x + xOff, y + yOff, genSpots);
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("z/Subworlds/BaseBlockNormal"), new Vector3(242 + 4 * x - 60, y * 4 - 60, 5), Quaternion.identity, 0);
                temp++;
                var position = new Vector3((float)(242 + x * 4 - 60), y * 4 - 60 + GetSizeForPixels(54) + 1.049f, 0f);

                if (random.Next(2) == 0)
                {
                  networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/SpaceOre1"), position, Quaternion.identity, 0);
                  temp++;
                }
                else
                {
                  networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/SpaceOre2"), position, Quaternion.identity, 0);
                  temp++;
                }
                break;
              case 3:
              case 4:
                for (int xOff = -1; xOff < 2; xOff++)
                  for (int yOff = -1; yOff < 2; yOff++)
                    MarkGeneration(x + xOff, y + yOff, genSpots);
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("z/Subworlds/BaseBlockSmall"), new Vector3(242 + 4 * x - 60, y * 4 - 60, 5), Quaternion.identity, 0);
                temp++;
                break;
              case 5:
                for (int xOff = -2; xOff < 3; xOff++)
                  for (int yOff = -2; yOff < 3; yOff++)
                    MarkGeneration(x + xOff, y + yOff, genSpots);
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("z/Subworlds/BaseBlockLarge"), new Vector3(242 + 4 * x - 60, y * 4 - 60, 5), Quaternion.identity, 0);
                temp++;
                break;
            }
          }
        }
      }
    }
  }
}
