using ActionGame.GameArtifacts.Models.Game;
using ActionGame.GameResources.Manager;
using ActionGame.RawResources.Manager;
using ActionGame.UserInterface.Core;
using ActionGame.UserInterface.Screen;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System;
using System.Collections.Generic;


namespace ActionGame
{
    public class GameEngine : Game, IScreenController
    {
        GraphicsDeviceManager graphics;
        private IDictionary<Screen.ScreenType, Screen> screens;
        private Screen.ScreenType activeScreen;

        public IResolution Resolution { get; }
        public SpriteBatch SpriteBatch { get; private set; }
        public IRawContentManager RawContentManager { get; private set; }
        public IGameContentManager GameContentManager { get; private set; }
        public GameData GameData { get; set; }
        public Song BackgroundMusic {get;set;}
        public TimeSpan LastKeyboardInputTime { get; set; }
        
        private TimeSpan lastResolutionInputTime;
        private Boolean fullScreen;


        public GameEngine()
        {
            fullScreen = false;

            //content
            Content.RootDirectory = "Content/bin";

            this.Window.Title = "Shattered Future";

            MediaPlayer.Volume = 0.05f; //HACK: Music Volume
            SoundEffect.MasterVolume = 0.05f; //HACK: Music Volume

            this.IsFixedTimeStep = true;                //assume 60fps
            this.Window.AllowUserResizing = true;

            //graphics, window, virtual resolution
            graphics = new GraphicsDeviceManager(this);

            this.Resolution = new Resolution(this.graphics)
            {
                GameWidth = 704,
                GameHeight = 384
            };

            SetupGraphics();

            this.Window.ClientSizeChanged += Window_ClientSizeChanged;
        }


        private void SetupGraphics()
        {
            graphics.IsFullScreen = fullScreen;

            if (fullScreen)
            {
                graphics.PreferredBackBufferWidth = 1280;
                graphics.PreferredBackBufferHeight = 720;
            }
            else
            {
                graphics.PreferredBackBufferWidth = 704;
                graphics.PreferredBackBufferHeight = 384;
            }

            graphics.ApplyChanges();
        }


        private void Window_ClientSizeChanged(object sender, EventArgs e)
        {
            ChangeResolution();
        }


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

            this.screens = new Dictionary<Screen.ScreenType, Screen>
            {
                { Screen.ScreenType.MainMenu, new MainMenuScreen(this) },
                { Screen.ScreenType.Game, new GameScreen(this) },
                { Screen.ScreenType.GameMenu, new GameMenuScreen(this) },
                { Screen.ScreenType.Inventory, new InventoryScreen(this) },
                { Screen.ScreenType.GameOver, new GameOverScreen(this) }
            };

            ChangeScreen(Screen.ScreenType.MainMenu);
        }


        protected override void LoadContent()
        {
            this.SpriteBatch = new SpriteBatch(GraphicsDevice);

            DateTime start = DateTime.Now;

            this.RawContentManager = new DefaultRawContentManager(this.Content);

            DateTime endRaw = DateTime.Now;

            this.GameContentManager = new DefaultGameContentManager(this.RawContentManager);

            DateTime endGame = DateTime.Now;

            System.Console.WriteLine("GameEngine.LoadContent - Completed");
            System.Console.WriteLine("Raw  " + (endRaw - start).TotalSeconds);
            System.Console.WriteLine("Game " + (endGame - endRaw).TotalSeconds);

            ChangeResolution();
        }


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


        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            if (lastResolutionInputTime == default(TimeSpan)) lastResolutionInputTime = gameTime.TotalGameTime;

            if (Keyboard.GetState().IsKeyDown(Keys.OemTilde))
            {
                if ((gameTime.TotalGameTime - lastResolutionInputTime).TotalSeconds > 1.0)
                {
                    this.Window.ClientSizeChanged -= Window_ClientSizeChanged;

                    fullScreen = !fullScreen;
                    SetupGraphics();
                    ChangeResolution();

                    this.Window.ClientSizeChanged += Window_ClientSizeChanged;

                    lastResolutionInputTime = gameTime.TotalGameTime;
                    this.LastKeyboardInputTime = gameTime.TotalGameTime;
                }
            }


            this.screens[this.activeScreen].Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);

            this.graphics.GraphicsDevice.Clear(Color.Black);

            this.SpriteBatch.Begin(transformMatrix: this.Resolution.TransformationMatrix, samplerState: SamplerState.PointClamp);

            this.screens[this.activeScreen].Draw(this.SpriteBatch, gameTime);

            SpriteBatch.End();
        }


        private void ChangeResolution()
        {
            if (this.Resolution != null)
            {
                this.Resolution.ActualWidth = this.Window.ClientBounds.Width;
                this.Resolution.ActualHeight = this.Window.ClientBounds.Height;
                this.Resolution.Update();
            }
        }


        public void ChangeScreen(Screen.ScreenType screenType)
        {
            this.activeScreen = screenType;

            this.screens[this.activeScreen].ActivateScreen();
        }

    }
}
