using System.Collections.Immutable;
using System.IO;
using Encompass;
using KavTest.Components;
using KavTest.Engines;
using KavTest.Extensions;
using KavTest.Messages;
using KavTest.Renderers;
using KavTest.Spawners;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MoonTools.Curve;

namespace KavTest
{
    class KavTestGame : Game
    {
        GraphicsDeviceManager graphics;

        WorldBuilder WorldBuilder { get; } = new WorldBuilder();
        World World { get; set; }

        public KavTestGame()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
            graphics.PreferMultiSampling = false;
            Content.RootDirectory = "Content";

            Window.AllowUserResizing = true;
            IsMouseVisible = true;

            Microsoft.Xna.Framework.Input.Mouse.IsRelativeMouseModeEXT = true;
        }

        protected override void LoadContent()
        {
            base.LoadContent();
        }

        protected override void UnloadContent()
        {
            base.UnloadContent();
        }

        protected override void Initialize()
        {
            base.Initialize();

            Texture2D.TextureDataFromStreamEXT(
                File.OpenRead("Content/Skybox/front.jpg"),
                out var skyboxSize,
                out _,
                out byte[] frontPixels
            );

            Texture2D.TextureDataFromStreamEXT(
                File.OpenRead("Content/Skybox/back.jpg"),
                out _,
                out _,
                out byte[] backPixels
            );

            Texture2D.TextureDataFromStreamEXT(
                File.OpenRead("Content/Skybox/right.jpg"),
                out _,
                out _,
                out byte[] rightPixels
            );

            Texture2D.TextureDataFromStreamEXT(
                File.OpenRead("Content/Skybox/left.jpg"),
                out _,
                out _,
                out byte[] leftPixels
            );

            Texture2D.TextureDataFromStreamEXT(
                File.OpenRead("Content/Skybox/top.jpg"),
                out _,
                out _,
                out byte[] topPixels
            );

            Texture2D.TextureDataFromStreamEXT(
                File.OpenRead("Content/Skybox/bottom.jpg"),
                out _,
                out _,
                out byte[] bottomPixels
            );

            var skybox = new TextureCube(GraphicsDevice, skyboxSize, false, SurfaceFormat.Color);
            skybox.SetData(CubeMapFace.PositiveZ, frontPixels);
            skybox.SetData(CubeMapFace.NegativeZ, backPixels);
            skybox.SetData(CubeMapFace.PositiveX, rightPixels);
            skybox.SetData(CubeMapFace.NegativeX, leftPixels);
            skybox.SetData(CubeMapFace.PositiveY, topPixels);
            skybox.SetData(CubeMapFace.NegativeY, bottomPixels);

            WorldBuilder.AddEngine(new InputEngine(this));
            WorldBuilder.AddEngine(new AngularVelocityEngine());
            WorldBuilder.AddEngine(new MoveAlongCurve3DEngine());
            WorldBuilder.AddEngine(new MotionEngine());
            WorldBuilder.AddEngine(new CameraEngine());
            WorldBuilder.AddEngine(new StaticModelSpawner());
            WorldBuilder.AddEngine(new DirectionalLightSpawner());
            WorldBuilder.AddGeneralRenderer(new SceneRenderer(GraphicsDevice), 0);

            WorldBuilder.SendMessage(new DirectionalLightSpawnMessage(
                //Quaternion.CreateFromAxisAngle(Vector3.Right, Microsoft.Xna.Framework.MathHelper.Pi / 3f),
                Quaternion.CreateFromAxisAngle(Vector3.Right, Microsoft.Xna.Framework.MathHelper.PiOver4),
                Color.LightGoldenrodYellow,
                0.7f
            ));

            var cameraEntity = WorldBuilder.CreateEntity();
            WorldBuilder.SetComponent(cameraEntity, new ArcballTransformComponent(
                new ArcballTransform(
                    new Vector3(0, 0, -10),
                    Microsoft.Xna.Framework.MathHelper.Pi,
                    0
                )
            ));
            WorldBuilder.SetComponent(cameraEntity, new PerspectiveCameraComponent(
                Microsoft.Xna.Framework.MathHelper.PiOver4,
                16f / 9f,
                0.01f,
                100f
            ));

            var skyboxEntity = WorldBuilder.CreateEntity();
            WorldBuilder.SetComponent(skyboxEntity, new SkyboxComponent(
                skybox
            ));

            World = WorldBuilder.Build();
        }

        protected override void Update(GameTime gameTime)
        {
            World.Update(gameTime.ElapsedGameTime.TotalSeconds);

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            World.Draw();

            base.Draw(gameTime);
        }
    }
}
