using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;
using System;
using System.Collections.Generic;

namespace LunaLightXMG
{
    public class Game1 : Game
    {
        // Class Objects
        private Player player;
        private PlayerInput playerInput;
        private List<Enemy> enemies;
        private int numOfEnemies;
        private GraphicsDeviceManager graphics;
        private SpriteBatch spriteBatch;

        // Native retro scale
        private int retroWidth = 320;
        private int retroHeight = 180;

        // Test Render Target
        private RenderTarget2D renderTarget;
        private Rectangle renderDestination;
        bool resizing;

        // Test sprites - eventually handle in a sprite manager?
        private Texture2D platformTexture;
        private Texture2D sinkArea;

        // Test platforms
        private Platform[] platforms;
        private int numOfPlatforms;

        // Music
        private SoundEffect sinkBeats;
        private SoundEffectInstance backgroundMusicInstance;

        // Debugging
        private SpriteFont debugFont;
        private Texture2D debugGrid;

        // Utility
        private static Random random; 

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;

            Window.ClientSizeChanged += OnClientSizeChanged;
            Window.AllowUserResizing = true;
            IsMouseVisible = true;

            // Test player input and movement with abstracted player class
            Vector2 initPlayerPosition = new Vector2(163, 0);
            player = new Player(initPlayerPosition);
            playerInput = new PlayerInput();
            enemies = new List<Enemy>();

            random = new Random(42);

            // Init number of platforms / enemies
            numOfPlatforms = 4;
            numOfEnemies = 10;
        }

        protected override void Initialize()
        {
            // Set initial window size
            graphics.PreferredBackBufferWidth = 1920;
            graphics.PreferredBackBufferHeight = 1080;
            graphics.ApplyChanges();

            playerInput.HasControl = true; // May need to find a new home for this

            base.Initialize();
            CalculateRenderDestination();
            // Play music
            // PlayBackgroundMusic(sinkBeats);

            // Generate random platforms - test this idea out...
            platforms = PlatformGenerator.CreatePlatforms(numOfPlatforms);
        }

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

            // Test platform
            platformTexture = Content.Load<Texture2D>("platform");
            sinkArea = Content.Load<Texture2D>("Sink area");
            // Music
            sinkBeats = Content.Load<SoundEffect>("music/sinkBeats");
            // load player sprite
            player.LoadContent(Content);  // player sprite is now handled in player.cs

            // Spawn 10 enemies at the start of the level
            enemies = SpawnEnemies(numOfEnemies); 

            // Test Render Target
            renderTarget = new RenderTarget2D(GraphicsDevice, retroWidth, retroHeight);

            // Debugging
            debugFont = Content.Load<SpriteFont>("fonts/debugFont");
            debugGrid = Content.Load<Texture2D>("debugGrid");
        }

        protected override void Update(GameTime gameTime)
        {
            // Temporary quit game - eventually handle in a pause menu class
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            // Check for game reset
            if (Keyboard.GetState().IsKeyDown(Keys.R))
                ResetGame();

            // Test player input and movement with abstracted player class
            playerInput.Update();
            player.Update(gameTime, playerInput, platforms);

            foreach (var enemy in enemies) {
                enemy.Update(gameTime, player, platforms);
            }

            base.Update(gameTime);
        }

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

            // Test Render Target - Draw sprites to the render target
            GraphicsDevice.SetRenderTarget(renderTarget);

            // Test Sprite
            spriteBatch.Begin(samplerState: SamplerState.PointClamp);
            // Debug Grid
            // spriteBatch.Draw(debugGrid, new Vector2(0, 0), Color.Blue);
            // spriteBatch.Draw(sinkArea, new Vector2(0, 0), Color.White);

            // Test draw tiles
            foreach (var platform in platforms)
            {
                platform.Draw(spriteBatch, platformTexture); // Assuming all tiles use the same texture for now
            }

            // Test player input and movement with abstracted player class
            player.Draw(spriteBatch);

            foreach (var enemy in enemies)
            {
                enemy.Draw(spriteBatch);
            }

            spriteBatch.End();


            // Test Render Target - Draw render target to the screen
            GraphicsDevice.SetRenderTarget(null);
            spriteBatch.Begin(samplerState: SamplerState.PointClamp);
            spriteBatch.Draw(renderTarget, renderDestination, Color.White);
            spriteBatch.End();

            // Debugging
            DrawDebugInfo();

            base.Draw(gameTime);
        }

        // Method Implementation -------------------------------------------------------------------------------
        private List<Enemy> SpawnEnemies(int numberOfEnemies) {
            List<Enemy> enemies = new List<Enemy>();
            for (int i = 0; i < numberOfEnemies; i++)
            {
                Vector2 spawnPosition = new Vector2(16 + i * 3, -16);
                Enemy enemy = new Enemy(spawnPosition, GetRandomValueBetween1And3());
                enemy.LoadContent(Content);
                enemies.Add(enemy);
            }
            return enemies;
        }

        private void PlayBackgroundMusic(SoundEffect backgroundMusic)
        {
            if (backgroundMusicInstance == null || backgroundMusicInstance.State != SoundState.Playing)
            {
                if (backgroundMusicInstance != null)
                {
                    backgroundMusicInstance.Dispose();
                }

                backgroundMusicInstance = backgroundMusic.CreateInstance();
                backgroundMusicInstance.IsLooped = true;
                backgroundMusicInstance.Play();
            }
        }

        private void OnClientSizeChanged(object sender, EventArgs eventArgs)
        {
            if (!resizing && Window.ClientBounds.Width > 0 && Window.ClientBounds.Height > 0)
            {
                resizing = true;
                CalculateRenderDestination();
                resizing = false;
            }
        }

        private void CalculateRenderDestination()  
        {
            Point size = GraphicsDevice.Viewport.Bounds.Size;

            // Calculate the integer scale factor
            int scaleX = size.X / renderTarget.Width;
            int scaleY = size.Y / renderTarget.Height;
            int scale = Math.Min(scaleX, scaleY);

            // Ensure the scale is at least 1
            scale = Math.Max(scale, 1);

            // Set renderDestination 
            renderDestination.Width = (int)(renderTarget.Width * scale);
            renderDestination.Height = (int)(renderTarget.Height * scale);

            renderDestination.X = (size.X - renderDestination.Width) / 2;
            renderDestination.Y = (size.Y - renderDestination.Height) / 2;
        }
        
        private void DrawDebugInfo()
        {
            spriteBatch.Begin();

            // Draw debug messages
            spriteBatch.DrawString(debugFont, $"VSP: {player.vsp}", new Vector2(10, 10), Color.White);
            spriteBatch.DrawString(debugFont, $"Grounded: {player.grounded}", new Vector2(10, 30), Color.White);
            spriteBatch.DrawString(debugFont, $"Walled: {player.walled}", new Vector2(10, 50), Color.White);
            spriteBatch.DrawString(debugFont, $"Position: {player.position}", new Vector2(10, 70), Color.White);

            spriteBatch.End();
        }

        public static float GetRandomValueBetween1And3()
        {
            return (float)(1 + 2 * random.NextDouble());
        }
        private void ResetGame()
        {
            // Reset player position
            player.Reset(new Vector2(163, 0));

            // Clear and respawn enemies
            enemies.Clear();
            enemies = SpawnEnemies(numOfEnemies);

            // Regenerate platforms
            platforms = PlatformGenerator.CreatePlatforms(numOfPlatforms);
        }
    }
}
