﻿using System;
using System.Collections.Generic;
using Oni.Imaging;

namespace Oni.Akira
{
    internal class PolygonMesh
    {
        private readonly MaterialLibrary materialLibrary;
        private readonly List<Vector3> points = new List<Vector3>();
        private readonly List<Vector3> normals = new List<Vector3>();
        private readonly List<Vector2> texCoords = new List<Vector2>();
        private readonly List<Polygon> polygons = new List<Polygon>();
        private readonly List<Polygon> doors = new List<Polygon>();
        private readonly List<Room> rooms = new List<Room>();
        private readonly List<Polygon> ghosts = new List<Polygon>();
        private readonly List<Polygon> floors = new List<Polygon>();
        private bool hasDebugInfo;

        public PolygonMesh(MaterialLibrary materialLibrary)
        {
            this.materialLibrary = materialLibrary;
        }

        public MaterialLibrary Materials => materialLibrary;

        public List<Vector3> Points => points;
        public List<Vector2> TexCoords => texCoords;
        public List<Vector3> Normals => normals;
        public List<Polygon> Polygons => polygons;
        public List<Polygon> Doors => doors;
        public List<Room> Rooms => rooms;
        public List<Polygon> Floors => floors;
        public List<Polygon> Ghosts => ghosts;

        public bool HasDebugInfo
        {
            get { return hasDebugInfo; }
            set { hasDebugInfo = value; }
        }

        public BoundingBox GetBoundingBox() => BoundingBox.CreateFromPoints(points);

        public void DoLighting()
        {
            var ambientColor = new Vector3(0.6f, 0.6f, 0.6f);

            var lightDir = new[] {
                new Vector3(-0.526f, -0.573f, -0.627f),
                new Vector3(0.719f, 0.342f, 0.604f),
                new Vector3(0.454f, 0.766f, 0.454f)
            };

            var lightColor = new[] {
                new Vector3(1.0f, 1.0f, 1.0f),
                new Vector3(1.0f, 1.0f, 1.0f),
                new Vector3(1.0f, 1.0f, 1.0f)
            };

            //if (importLights)
            //{
            //    ambientColor = ambient;
            //}

            foreach (var polygon in polygons)
            {
                if (polygon.Colors != null)
                    continue;

                var colors = new Color[polygon.VertexCount];

                if (polygon.NormalIndices != null)
                {
                    for (int i = 0; i < colors.Length; i++)
                    {
                        var color = ambientColor;

                        for (int j = 0; j < lightDir.Length; j++)
                        {
                            float dot = Vector3.Dot(lightDir[j], normals[polygon.NormalIndices[i]]);
                            color += lightColor[j] * dot;
                        }

                        colors[i] = new Color(Vector3.Clamp(color, Vector3.Zero, Vector3.One));
                    }
                }
                else
                {
                    var color = ambientColor;

                    for (int j = 0; j < lightDir.Length; j++)
                    {
                        float dot = Vector3.Dot(lightDir[j], polygon.Plane.Normal);
                        color += lightColor[j] * dot;
                    }

                    for (int i = 0; i < colors.Length; i++)
                        colors[i] = new Color(Vector3.Clamp(color, Vector3.Zero, Vector3.One));
                }

                polygon.Colors = colors;
            }
        }
    }
}
