using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Toolbox.Library;
using Toolbox.Library.Rendering;
using System.Windows.Forms;
using OpenTK;
using System.Linq;

namespace FirstPlugin
{
    public class CsvModel : IFileFormat
    {
        public FileType FileType { get; set; } = FileType.Spreadsheet;

        public bool CanSave { get; set; }
        public string[] Description { get; set; } = new string[] { "CSV Model" };
        public string[] Extension { get; set; } = new string[] { "*.csv" };
        public string FileName { get; set; }
        public string FilePath { get; set; }
        public IFileInfo IFileInfo { get; set; }

        public bool Identify(System.IO.Stream stream)
        {
            return false;
        }

        public Type[] Types
        {
            get
            {
                List<Type> types = new List<Type>();
                return types.ToArray();
            }
        }

        public List<STGenericObject> objects = new List<STGenericObject>();

        public class Model
        {
            public string Name { get; set; }
            public int UVChannelCount { get; set; }
            public DataType type;
            public DataSubType subType;

            public List<string[]> bones = new List<string[]>();
            public List<float[]> weights = new List<float[]>();
        }
        public enum DataType : int
        {
            vertex = 1,
            faces = 2,
            bones = 3,
        }
        public enum DataSubType : int
        {
            position = 0,
            normals = 1,
            colors = 2,
            uv0 = 3,
            uv1 = 4,
            uv2 = 5,
            uv3 = 6,
        }

        float X, Y, Z, W;
        public void Load(System.IO.Stream stream)
        {
            LoadFile(stream);
        }
        public void LoadFile(Stream stream, bool IsModel = false)
        {
            if (!IsModel)
            {
                MessageBox.Show("Not valid model csv");
                return;
            }

            string line = null;

            List<Model> models = new List<Model>();

            TextReader csv = new StreamReader(stream);
            Model model = new Model();
            STGenericObject STobj = new STGenericObject();
            Vertex vtx = new Vertex();
            STGenericObject.LOD_Mesh lod = new STGenericObject.LOD_Mesh();
            int Index = 0;
            while (true)
            {
                line = csv.ReadLine();
                if (line != null)
                {
                    if (line.StartsWith("Obj Name"))
                    {
                        model = new Model();
                        STobj = new STGenericObject();
                        model.Name = line.Split(':')[1].Replace("\n", "");
                        model.subType = DataSubType.position;
                        models.Add(model);

                        STobj.ObjectName = model.Name;
                        lod = new STGenericObject.LOD_Mesh();
                        lod.IndexFormat = STIndexFormat.UInt16;
                        lod.PrimativeType = STPrimitiveType.Triangles;
                        STobj.lodMeshes.Add(lod);
                        STobj.VertexBufferIndex = Index;
                        objects.Add(STobj);
                        Index++;
                    }
                    else if (line.StartsWith("tex_Array:"))
                    {

                    }
                    else if (line.StartsWith("Bone_Suport"))
                    {

                    }
                    else if (line.StartsWith("Color_Suport"))
                    {

                    }
                    else if (line.StartsWith("UV_Num:"))
                    {
                        int uvCount;
                        int.TryParse(line.Split(':')[1].Replace("\n", ""), out uvCount);
                        model.UVChannelCount = uvCount;
                    }
                    else if (line.StartsWith("vert_Array"))
                    {
                        model.type = DataType.vertex;
                    }
                    else if (line.StartsWith("face_Array"))
                    {
                        model.type = DataType.faces;
                    }
                    else if (line.StartsWith("bone_Array"))
                    {
                        model.type = DataType.bones;
                    }
                    else
                    {
                        string[] values = line.Replace("\n", "").Replace("\r", "").Split(',');

                        if (model.type == DataType.vertex)
                        {
                            switch (model.subType)
                            {
                                case DataSubType.position:
                                    vtx = new Vertex();
                                    STobj.vertices.Add(vtx);

                                    STobj.HasPos = true;

                                    float.TryParse(values[0], out X);
                                    float.TryParse(values[1], out Y);
                                    float.TryParse(values[2], out Z);
                                    vtx.pos = new Vector3(X, Y, Z);
                                    model.subType = DataSubType.normals;
                                    break;
                                case DataSubType.normals:
                                    STobj.HasNrm = true;

                                    float.TryParse(values[0], out X);
                                    float.TryParse(values[1], out Y);
                                    float.TryParse(values[2], out Z);
                                    vtx.nrm = new Vector3(X, Y, Z);
                                    model.subType = DataSubType.colors;
                                    break;
                                case DataSubType.colors:
                                    STobj.HasVertColors = true;

                                    float.TryParse(values[0], out X);
                                    float.TryParse(values[1], out Y);
                                    float.TryParse(values[2], out Z);
                                    float.TryParse(values[3], out W);
                                    vtx.col = new Vector4(X / 255, Y / 255, Z / 255, 1);
                                    model.subType = DataSubType.uv0;
                                    break;
                                case DataSubType.uv0:
                                    STobj.HasUv0 = true;

                                    float.TryParse(values[0], out X);
                                    float.TryParse(values[1], out Y);
                                    vtx.uv0 = new Vector2(X, 1 - Y);
                                    if (model.UVChannelCount == 1)
                                        model.subType = DataSubType.position;
                                    else
                                        model.subType = DataSubType.uv1;
                                    break;
                                case DataSubType.uv1:
                                    STobj.HasUv1 = true;

                                    float.TryParse(values[0], out X);
                                    float.TryParse(values[1], out Y);
                                    vtx.uv1 = new Vector2(X, 1 - Y);
                                    if (model.UVChannelCount == 2)
                                        model.subType = DataSubType.position;
                                    else
                                        model.subType = DataSubType.uv2;
                                    break;
                                case DataSubType.uv2:
                                    STobj.HasUv2 = true;

                                    float.TryParse(values[0], out X);
                                    float.TryParse(values[1], out Y);
                                    vtx.uv2 = new Vector2(X, 1 - Y);
                                    if (model.UVChannelCount == 3)
                                        model.subType = DataSubType.position;
                                    else
                                        model.subType = DataSubType.uv3;
                                    break;
                                case DataSubType.uv3:
                                    float.TryParse(values[0], out X);
                                    float.TryParse(values[1], out Y);
                                    model.subType = DataSubType.position;
                                    break;
                            }
                        }
                        if (model.type == DataType.faces)
                        {
                            int face;
                            foreach (string v in values)
                            {
                                var cleaned = v.Replace(".0", string.Empty);
                                int.TryParse(cleaned, out face);
                                lod.faces.Add(face-1);
                            }
                        }
                        if (model.type == DataType.bones)
                        {
                            STobj.HasWeights = true;
                            STobj.HasIndices = true;

                            Array.Resize(ref values, values.Length - 1);

                            List<string> bones = new List<string>();
                            List<float> weights = new List<float>();

                            int bbs = 0;
                            foreach (string obj in values)
                            {
                                if (bbs == 0)
                                {
                                    bones.Add(obj);
                                    bbs += 1;
                                }
                                else
                                {
                                    float.TryParse(obj, out X);
                                    weights.Add(X);
                                    bbs = 0;
                                }
                            }

                            STobj.bones.Add(bones.ToArray());
                            STobj.weightsT.Add(weights.ToArray());
                        }
                    }
                }
                else
                    break;
            }

            if (objects[0].weightsT.Count > 0 && objects[0].weightsT.Count != objects[0].vertices.Count)
                throw new Exception("Incorrect vertex amount");

            foreach (STGenericObject obj in objects)
            {
                obj.lodMeshes[0].GenerateSubMesh();
                for (int v = 0; v < obj.vertices.Count; v++)
                {
                    foreach (string bn in obj.bones[v])
                        obj.vertices[v].boneNames.Add(bn);
                    foreach (float f in obj.weightsT[v])
                        obj.vertices[v].boneWeights.Add(f);
                }
                obj.VertexSkinCount = (byte)obj.vertices.Max(v => v.boneNames.Count);

                int vID = 0;
                foreach (Vertex v in obj.vertices)
                {
                    if (v.boneNames.Count == 1)
                        Console.WriteLine($"{vID} {v.boneNames[0]} {v.boneWeights[0]}");
                    if (v.boneNames.Count == 2)
                        Console.WriteLine($"{vID} {v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]}");
                    if (v.boneNames.Count == 3)
                        Console.WriteLine($"{vID} {v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]} {v.boneNames[2]} {v.boneWeights[2]}");
                    if (v.boneNames.Count == 4)
                        Console.WriteLine($"{vID} {v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]} {v.boneNames[2]} {v.boneWeights[2]} {v.boneNames[3]} {v.boneWeights[3]}");

                    vID++;
                }
            }

            csv.Close();
            csv = null;
        }
        public void Unload()
        {

        }
        public void Save(System.IO.Stream stream)
        {
            using (System.IO.StreamWriter file = new System.IO.StreamWriter(stream))
            {
                foreach (STGenericObject obj in objects)
                {
                    file.WriteLine($"Obj Name:" + obj.ObjectName);
                    file.WriteLine($"Bone_Suport");
                    file.WriteLine($"UV_Num:1");
                    file.WriteLine($"vert_Array");

                    foreach (Vertex v in obj.vertices)
                    {
                        file.WriteLine($"{v.pos.X},{v.pos.Y},{v.pos.Z}");
                        file.WriteLine($"{v.nrm.X},{v.nrm.Y},{v.nrm.Z}");
                        file.WriteLine($"{v.col.X * 255},{v.col.Y * 255},{v.col.Z * 255},{v.col.W * 255}");
                        file.WriteLine($"{v.uv0.X},{v.uv0.Y}");
                   //     file.WriteLine($"{v.uv1.X},{v.uv1.Y}");
                    }
                    file.WriteLine($"face_Array");
                    for (int f = 0; f < obj.faces.Count / 3; f++)
                    {
                        file.WriteLine($"{obj.faces[f] + 1},{obj.faces[f++] + 1},{obj.faces[f++] + 1}");
                    }
                    file.WriteLine($"bone_Array");
                    foreach (Vertex v in obj.vertices)
                    {
                        if (v.boneNames.Count == 1)
                            file.WriteLine($"{v.boneNames[0]} {v.boneWeights[0]}");
                        if (v.boneNames.Count == 2)
                            file.WriteLine($"{v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]}");
                        if (v.boneNames.Count == 3)
                            file.WriteLine($"{v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]} {v.boneNames[2]} {v.boneWeights[2]}");
                        if (v.boneNames.Count == 4)
                            file.WriteLine($"{v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]} {v.boneNames[2]} {v.boneWeights[2]} {v.boneNames[3]} {v.boneWeights[3]}");
                    }
                }
                file.Close();
            }
        }
    }
}
