using System.Collections.Generic;
using UnityEngine;

public class PlaneGenerator : MonoBehaviour
{
    public Material material;

    private const int pqsResolution = 16;
    private const int sphereRadius = 10;

    private List<Quad> quads;

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        BuildRootQuads();
    }

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

    private void BuildRootQuads()
    {
        var (vertices, uv) = CreateVertices();
        var triangles = CreateTriangles();
        RotatePlaneY(vertices);
        CreateMesh("mesh_Y", vertices, uv, triangles);

        (vertices, uv) = CreateVertices();
        triangles = CreateTriangles();
        RotatePlaneY1(vertices);
        CreateMesh("mesh_Y1", vertices, uv, triangles);

        (vertices, uv) = CreateVertices();
        triangles = CreateTriangles();
        RotatePlaneZ(vertices);
        CreateMesh("mesh_Z", vertices, uv, triangles);

        (vertices, uv) = CreateVertices();
        triangles = CreateTriangles();
        RotatePlaneZ1(vertices);
        CreateMesh("mesh_Z1", vertices, uv, triangles);

        (vertices, uv) = CreateVertices();
        triangles = CreateTriangles();
        RotatePlaneX(vertices);
        CreateMesh("mesh_X", vertices, uv, triangles);

        (vertices, uv) = CreateVertices();
        triangles = CreateTriangles();
        RotatePlaneX1(vertices);
        CreateMesh("mesh_X1", vertices, uv, triangles);
    }

    private (Vector3[] vertices, Vector2[] uv) CreateVertices()
    {
        var half = sphereRadius / 2f;
        var vertices = new Vector3[(pqsResolution + 1) * (pqsResolution + 1)];
        Vector2[] uv = new Vector2[(pqsResolution + 1) * (pqsResolution + 1)];

        for (int x = 0, vertex = 0; x < pqsResolution + 1; x++)
        {
            for (int z = 0; z < pqsResolution + 1; z++, vertex++)
            {
                vertices[vertex] = new Vector3(half - (float)x / pqsResolution * sphereRadius, half, half - (float)z / pqsResolution * sphereRadius);
                uv[vertex] = new Vector2((float)x / pqsResolution, (float)z / pqsResolution);
            }
        }

        return (vertices, uv);

    }

    private int[] CreateTriangles()
    {
        var triangles = new int[(pqsResolution) * (pqsResolution) * 6];

        int triangle = 0;
        for (int x = 1, vertex = 0; x<pqsResolution + 1; x++, vertex++)
        {
            for (int z = 1; z<pqsResolution + 1; z++, vertex++)
            {
                triangles[triangle] = vertex;
                triangles[triangle + 1] = vertex + pqsResolution + 2;
                triangles[triangle + 2] = vertex + pqsResolution + 1;

                triangles[triangle + 3] = vertex;
                triangles[triangle + 4] = vertex + 1;
                triangles[triangle + 5] = vertex + pqsResolution + 2;

                triangle += 6;
            }
        }

        return triangles;
    }

    private void CreateMesh(string name, Vector3[] vertices, Vector2[] uv, int[] triangles)
    {
        var mesh = new GameObject(name, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider));
        mesh.transform.localScale = new Vector3(1, 1, 1);

        var meshFilter = mesh.GetComponent<MeshFilter>();
        meshFilter.mesh.vertices = vertices;
        meshFilter.mesh.triangles = triangles;
        meshFilter.mesh.uv = uv;

        mesh.GetComponent<MeshCollider>().sharedMesh = meshFilter.mesh;
        meshFilter.mesh.RecalculateBounds();
        meshFilter.mesh.RecalculateNormals();

        mesh.GetComponent<MeshRenderer>().material = material;
    }

    private void RotatePlaneZ(Vector3[] vertices)
    {
        for (int x = 0, vertex = 0; x < pqsResolution + 1; x++)
        {
            for (int z = 0; z < pqsResolution + 1; z++, vertex++)
            {
                vertices[vertex] = new Vector3(-vertices[vertex].x, vertices[vertex].z, vertices[vertex].y);
                vertices[vertex] = Vector3.Normalize(vertices[vertex]) * sphereRadius;
            }
        }
    }

    private void RotatePlaneY(Vector3[] vertices)
    {
        for (int x = 0, vertex = 0; x < pqsResolution + 1; x++)
        {
            for (int z = 0; z < pqsResolution + 1; z++, vertex++)
            {
                vertices[vertex] = Vector3.Normalize(vertices[vertex]) * sphereRadius;
            }
        }
    }

    private void RotatePlaneZ1(Vector3[] vertices)
    {
        for (int x = 0, vertex = 0; x < pqsResolution + 1; x++)
        {
            for (int z = 0; z < pqsResolution + 1; z++, vertex++)
            {
                vertices[vertex] = new Vector3(-vertices[vertex].x, -vertices[vertex].z, -vertices[vertex].y);
                vertices[vertex] = Vector3.Normalize(vertices[vertex]) * sphereRadius;
            }
        }
    }

    private void RotatePlaneX(Vector3[] vertices)
    {
        for (int x = 0, vertex = 0; x < pqsResolution + 1; x++)
        {
            for (int z = 0; z < pqsResolution + 1; z++, vertex++)
            {
                vertices[vertex] = new Vector3(vertices[vertex].y, vertices[vertex].x, -vertices[vertex].z);
                vertices[vertex] = Vector3.Normalize(vertices[vertex]) * sphereRadius;
            }
        }
    }

    private void RotatePlaneY1(Vector3[] vertices)
    {
        for (int x = 0, vertex = 0; x < pqsResolution + 1; x++)
        {
            for (int z = 0; z < pqsResolution + 1; z++, vertex++)
            {
                vertices[vertex] = new Vector3(-vertices[vertex].x, -vertices[vertex].y, vertices[vertex].z);
                vertices[vertex] = Vector3.Normalize(vertices[vertex]) * sphereRadius;
            }
        }
    }

    private void RotatePlaneX1(Vector3[] vertices)
    {
        for (int x = 0, vertex = 0; x < pqsResolution + 1; x++)
        {
            for (int z = 0; z < pqsResolution + 1; z++, vertex++)
            {
                vertices[vertex] = new Vector3(-vertices[vertex].y, -vertices[vertex].x, -vertices[vertex].z);
                vertices[vertex] = Vector3.Normalize(vertices[vertex]) * sphereRadius;
            }
        }
    }
}
