using GadgetCore.API;
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

namespace Subworlds
{
  internal enum ShipGeneratorObjectPoolType
  {
    SmallObject = 0,
    LargeObject = 1,
    FlyingEnemy = 2,
    BrokenItemMod = 3,
    BrokenChest = 4,
    OldChest = 5,
    BrokenLaser = 6
  }

  public class ShipGenerator
  {
    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("Ship/parallax.png") };

    private static readonly Material materialaParalexStars = new Material(Shader.Find("Unlit/Transparent")) { mainTexture = GadgetCoreAPI.LoadTexture2D("Ship/bgStars.png") };
    private static readonly Material materialaParalexNone = new Material(Shader.Find("Unlit/Transparent")) { mainTexture = GadgetCoreAPI.LoadTexture2D("Ship/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);

    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/ShuttleMain"), 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)
    {
      try
      {
        GameScript.isTown = false;

        spawnLocations.Clear();

        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/ShipAEntrance"), new Vector3((float)(218 + 0 * 128), 0f, 5f), Quaternion.Euler(0f, 180f, 180f));
        num++;
        chunks[num] = (GameObject)UnityEngine.Object.Instantiate(Resources.Load("z/Subworlds/ShipAMain"), new Vector3((float)(218 + 0.75 * 128), 0f, 5f), Quaternion.Euler(0f, 180f, 180f));
        num++;

        spawnLocations.Add(new int[] { 7, 7, (int)ShipGeneratorObjectPoolType.FlyingEnemy });
        spawnLocations.Add(new int[] { 10, 7, (int)ShipGeneratorObjectPoolType.FlyingEnemy });
        spawnLocations.Add(new int[] { 16, 7, (int)ShipGeneratorObjectPoolType.FlyingEnemy });
        spawnLocations.Add(new int[] { 17, 4, (int)ShipGeneratorObjectPoolType.FlyingEnemy });

        spawnLocations.Add(new int[] { 32, 0, (int)ShipGeneratorObjectPoolType.BrokenLaser });

        Add4(4, 0);
        Add4(4, 5);
        Add4Floor(4, -5);

        Add4(10, 0);
        Add4(10, 5);
        Add4Floor(10, -5);

        Add4(20, 0);
        Add4(20, 5);
        Add4Floor(20, -5);

        Add4(26, 0);
        Add4(26, 5);
        Add4Floor(26, -5);

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

        spawnLocations.Add(new int[] { 7 + 32, 7, (int)ShipGeneratorObjectPoolType.FlyingEnemy });
        spawnLocations.Add(new int[] { 10 + 32, 7, (int)ShipGeneratorObjectPoolType.FlyingEnemy });
        spawnLocations.Add(new int[] { 16 + 32, 7, (int)ShipGeneratorObjectPoolType.FlyingEnemy });
        spawnLocations.Add(new int[] { 17 + 32, 4, (int)ShipGeneratorObjectPoolType.FlyingEnemy });

        spawnLocations.Add(new int[] { 32 + 32, 0, (int)ShipGeneratorObjectPoolType.BrokenLaser });

        Add4(4 + 32, 0);
        Add4(4 + 32, 5);
        Add4Floor(4 + 32, -5);

        Add4(10 + 32, 0);
        Add4(10 + 32, 5);
        Add4Floor(10 + 32, -5);

        Add4(20 + 32, 0);
        Add4(20 + 32, 5);
        Add4Floor(20 + 32, -5);

        Add4(26 + 32, 0);
        Add4(26 + 32, 5);
        Add4Floor(26 + 32, -5);

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

        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 void Add4(int x, int y)
    {
      var r = random.Next(8);
      switch (r)
      {
        case 0:
          spawnLocations.Add(new int[] { x + 1, y, (int)ShipGeneratorObjectPoolType.LargeObject });
          break;
        case 1:
          spawnLocations.Add(new int[] { x + 2, y, (int)ShipGeneratorObjectPoolType.LargeObject });
          break;
        case 2:
          spawnLocations.Add(new int[] { x + 0, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          spawnLocations.Add(new int[] { x + 2, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          spawnLocations.Add(new int[] { x + 3, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          break;
        case 3:
          spawnLocations.Add(new int[] { x + 0, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          spawnLocations.Add(new int[] { x + 1, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          spawnLocations.Add(new int[] { x + 3, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          break;
        case 4:
          spawnLocations.Add(new int[] { x + 1, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          spawnLocations.Add(new int[] { x + 3, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          break;
        case 5:
          spawnLocations.Add(new int[] { x + 0, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          spawnLocations.Add(new int[] { x + 2, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          break;
        case 6:
          if (random.Next(2) == 0)
          {
            spawnLocations.Add(new int[] { x + 1, y, (int)ShipGeneratorObjectPoolType.BrokenItemMod });
            spawnLocations.Add(new int[] { x + 2, y, (int)ShipGeneratorObjectPoolType.BrokenChest });
          }
          else
          {
            spawnLocations.Add(new int[] { x + 1, y, (int)ShipGeneratorObjectPoolType.BrokenChest });
            spawnLocations.Add(new int[] { x + 2, y, (int)ShipGeneratorObjectPoolType.BrokenItemMod });
          }
          break;
        case 7:
          if (random.Next(2) == 0)
          {
            spawnLocations.Add(new int[] { x + 1, y, (int)ShipGeneratorObjectPoolType.SmallObject });
            spawnLocations.Add(new int[] { x + 2, y, (int)ShipGeneratorObjectPoolType.OldChest });
          }
          else
          {
            spawnLocations.Add(new int[] { x + 1, y, (int)ShipGeneratorObjectPoolType.OldChest });
            spawnLocations.Add(new int[] { x + 2, y, (int)ShipGeneratorObjectPoolType.SmallObject });
          }
          break;
      }
    }
    private static void Add4Floor(int x, int y)
    {
      if (random.Next(2) == 0)
        Add4(x, y);
      else
      {
        var r = random.Next(5);
        switch (r)
        {
          case 0:
            spawnLocations.Add(new int[] { x + 0, y, (int)ShipGeneratorObjectPoolType.LargeObject });
            break;
          case 1:
            spawnLocations.Add(new int[] { x + 3, y, (int)ShipGeneratorObjectPoolType.LargeObject });
            break;
          case 2:
            spawnLocations.Add(new int[] { x + 0, y, (int)ShipGeneratorObjectPoolType.LargeObject });
            spawnLocations.Add(new int[] { x + 3, y, (int)ShipGeneratorObjectPoolType.LargeObject });
            break;
          case 3:
            spawnLocations.Add(new int[] { x + 1, y, (int)ShipGeneratorObjectPoolType.LargeObject });
            spawnLocations.Add(new int[] { x + 3, y, (int)ShipGeneratorObjectPoolType.LargeObject });
            break;
          case 4:
            spawnLocations.Add(new int[] { x + 0, y, (int)ShipGeneratorObjectPoolType.LargeObject });
            spawnLocations.Add(new int[] { x + 2, y, (int)ShipGeneratorObjectPoolType.LargeObject });
            break;
        }
      }
    }

    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 * 0, -6.118f, 0.3f), Quaternion.identity, 0);
        temp++;
        networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("npc2103"), new Vector3(248f + 4 * 1, -6.118f, 0.3f), Quaternion.identity, 0);
        temp++;
        networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("npc/npcQuest"), new Vector3(248f + 4 * 3, -6.118f, 0.3f), Quaternion.identity, 0);
        temp++;
      }
      catch (Exception e) { Core.logger.LogError(e); }

      GameScript.endPortal[0] = (GameObject)Network.Instantiate((GameObject)Resources.Load("portal"), new Vector3(248f + 4 * 5, -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.shipPlanet.GetID() : Core.lastBiome, 0, 0 });

      GameScript.endPortal[3] = (GameObject)Network.Instantiate((GameObject)Resources.Load("portal"), new Vector3(248f - 4 * 2, -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);

      try
      {

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

        networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenTeleporter"), new Vector3(248f - 4 * 1, -4f + 0.118f, 0.3f), Quaternion.identity, 0);
        temp++;


        foreach (var e in spawnLocations)
        {
          switch ((ShipGeneratorObjectPoolType)e[2])
          {
            case ShipGeneratorObjectPoolType.SmallObject:
              if (random.Next(30) == 0)
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenItemMod"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 4 * e[1], 0.2f), Quaternion.identity, 0);
              else if (random.Next(4) == 0)
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenCrates1"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 4 * e[1], 0.2f), Quaternion.identity, 0);
              else if (random.Next(3) == 0)
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenCrates2"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 4 * e[1], 0.2f), Quaternion.identity, 0);
              else if (random.Next(2) == 0)
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenCrates3"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 4 * e[1], 0.2f), Quaternion.identity, 0);
              else
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenCrates4"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 4 * e[1], 0.2f), Quaternion.identity, 0);
              break;
            case ShipGeneratorObjectPoolType.LargeObject:
              if (random.Next(6) == 0)
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenPirate1"), new Vector3(248f + 4 * e[0], -5.75f + 0.118f + 4 * e[1], 0.2f), Quaternion.identity, 0);
              else if (random.Next(5) == 0)
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenPirate2"), new Vector3(248f + 4 * e[0], -5.75f + 0.118f + 4 * e[1], 0.2f), Quaternion.identity, 0);
              else if (random.Next(4) == 0)
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenPirate3"), new Vector3(248f + 4 * e[0], -5.75f + 0.118f + 4 * e[1], 0.2f), Quaternion.identity, 0);
              else if (random.Next(3) == 0)
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenPirate4"), new Vector3(248f + 4 * e[0], -5.75f + 0.118f + 4 * e[1], 0.2f), Quaternion.identity, 0);
              else if (random.Next(2) == 0)
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenPirate5"), new Vector3(248f + 4 * e[0], -5.75f + 0.118f + 4 * e[1], 0.2f), Quaternion.identity, 0);
              else
                networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenPirate6"), new Vector3(248f + 4 * e[0], -5.75f + 0.118f + 4 * e[1], 0.2f), Quaternion.identity, 0);
              break;
            case ShipGeneratorObjectPoolType.FlyingEnemy:
              Network.Instantiate(Resources.Load("e/Subworlds/BrokenSliver"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 1.1f + 4 * e[1], 0f), Quaternion.identity, 0);
              Network.Instantiate(Resources.Load("e/Subworlds/BrokenDroid"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 1.1f + 4 * e[1], 0f), Quaternion.identity, 0);
              break;
            case ShipGeneratorObjectPoolType.BrokenItemMod:
              networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenItemMod"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 4 * e[1], 0.2f), Quaternion.identity, 0);
              break;
            case ShipGeneratorObjectPoolType.BrokenChest:
              networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/BrokenChest"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 4 * e[1], 0.2f), Quaternion.identity, 0);
              break;
            case ShipGeneratorObjectPoolType.OldChest:
              networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("obj/Subworlds/OldChest"), new Vector3(248f + 4 * e[0], -8f + 0.118f * 4 + 4 * e[1], 0.2f), Quaternion.identity, 0);
              break;
            case ShipGeneratorObjectPoolType.BrokenLaser:
              networkStuff[temp] = (GameObject)Network.Instantiate(Resources.Load("haz/Subworlds/LaserHazard"), new Vector3(248f + 4 * (e[0] + 0.5f), 4 * (e[1]), 0.2f), Quaternion.identity, 0);
              break;
          }
          if (networkStuff[temp] != null)
            temp++;
        }
      }
      catch (Exception e) { Core.logger.LogError(e); }

      GameScript.endPortal[0] = (GameObject)Network.Instantiate((GameObject)Resources.Load("portal"), new Vector3(248f + 4 * 38 + 128, -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.shipPlanet.GetID(), 0, 0 });
    }
  }
}
