using LeMangeurDEnfants.Core.Entities;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using MonoGame.FourEngine;
using MonoGame.FourEngine.Entities;
using MonoGame.FourEngine.Extensions;
using MonoGame.FourEngine.Interfaces;
using MonoGame.FourEngine.Tiled;
using System;
using System.Collections.Generic;
using System.Linq;

namespace LeMangeurDEnfants.Core.Scenes
{
    public class GameScene : Scene
    {
        public static readonly Point TileSize = new Point(16);
        public Background Background { get; }
        public CameraEntity Camera { get; }
        public List<Wall> Walls { get; }
        public BigBoss BigBoss { get; }

        public Rectangle MapBorder { get; }

        private Vector2 _cameraPosition;

        public GameScene()
        {
            AddEntity(Background = new Background());
            AddEntity(Camera = new CameraEntity());
            var map = this
                .AddMap(new Map(Resources.Maps.Map0)).ToList();
            Walls = map
                .Filter<Wall>()
                .ToList();
            BigBoss = map.Filter<BigBoss>().FirstOrDefault();
            var tiles = map.Filter<TiledEntity>().ToList();
            MapBorder = new Rectangle(
                tiles.Min(x => x.Position.X),
                tiles.Min(x => x.Position.Y),
                tiles.Max(x => x.Position.X + x.Width),
                tiles.Max(x => x.Position.Y + x.Height));
            AddEntity(new IndicatorPistol
            {
                Position = Configuration.InnerResolution - new Point(18, 15)
            });

            foreach (var mapElement in map.Filter<ICanTransform>())
            {
                Camera.AttachTo(mapElement);
            }
            Camera.Position = CalculateOptimalCameraPosition();
            _cameraPosition = Camera.Position.ToVector2();
        }

        public override void OnUpdate(UpdateEventArgs args)
        {
            base.OnUpdate(args);
            ParallaxBackground();
            CenterCamera();
            if (args.Keyboard.State[Keys.F5].HasClicked || args.GamePad.State[Buttons.Back].HasClicked)
            {
                Restart();
            }
        }

        public void Restart()
        {
            (DrawingSurface as DrawingSurface)?.NavigateTo<GameScene>();
        }
        
        public void Win()
        {
            (DrawingSurface as DrawingSurface)?.NavigateTo<OutroScene>();
        }

        private void ParallaxBackground()
        {
            if (BigBoss != null)
            {
                double posX = BigBoss.Position.X - MapBorder.Left;
                double posY = BigBoss.Position.Y - MapBorder.Top;
                var percentX = posX / MapBorder.Width;
                var percentY = posY / MapBorder.Height;
                if (percentX < 0) percentX = 0;
                if (percentX > 1) percentX = 0;
                if (percentY < 0) percentY = 0;
                if (percentY > 1) percentY = 0;
                var percent = 1 - (percentX + percentY) / 2;
                Background.Position = new Point(0, (int)(Background.LimitY * percent));
            }
        }

        private void CenterCamera()
        {
            if (BigBoss != null)
            {
                var target = CalculateOptimalCameraPosition();
                _cameraPosition = _cameraPosition * 0.95f + target.ToVector2() * 0.05f;
                Camera.Position = _cameraPosition.ToPoint();
            }
        }

        private Point CalculateOptimalCameraPosition()
        {
            var cameraPosition = Entities
                .Filter<CameraPosition>()
                .OrderBy(x => Math.Abs((x.Position.ToVector2() - BigBoss.Position.ToVector2()).Length()))
                .FirstOrDefault()?.Position ?? BigBoss.Position;
            return cameraPosition - new Point(Configuration.InnerResolution.X / 2, Configuration.InnerResolution.Y / 2);
        }

        public override void OnClear(ClearEventArgs args)
        {
            args.Color = Color.DarkBlue;
        }
    }
}