using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using MonoGame.FourEngine.Extensions;

namespace MonoGame.FourEngine.Services
{
    public class BasicGamePadControl : IGamePadControl
    {
        protected static readonly TimeSpan RepeatTime = TimeSpan.FromMilliseconds(500);

        public IReadOnlyDictionary<Buttons, KeyState> State { get; }
        public Vector2 LeftStick { get; private set; }
        public Vector2 RightStick { get; private set; }

        private IDictionary<Buttons, TimeSpan> _repeat;

        public BasicGamePadControl()
        {
            State = Enum
                .GetValues(typeof(Buttons))
                .Cast<Buttons>()
                .ToDictionary(x => x, x => new KeyState())
                .ToReadOnly();
            _repeat = State.Keys
                .ToDictionary(x => x, x => TimeSpan.Zero);
        }

        public void Update(TimeSpan deltaTime)
        {
            var gamePadState = GamePad.GetState(0);
            if (gamePadState.IsConnected)
            {
                LeftStick = gamePadState.ThumbSticks.Left;
                RightStick = gamePadState.ThumbSticks.Right;
            }
            foreach (var state in State.Values.Where(x => x.WasPressed))
            {
                state.WasPressed = false;
            }
            foreach (var state in State.Values.Where(x => x.IsPressed))
            {
                state.WasPressed = true;
                state.IsPressed = false;
                state.ClickCancellable.Reset();
            }
            var pressedKeys = RetrievePressedButtons(gamePadState);
            foreach (var key in pressedKeys)
            {
                if (State.ContainsKey(key))
                {
                    State[key].IsPressed = true;
                    _repeat[key] += deltaTime;
                    if (_repeat[key] >= RepeatTime)
                    {
                        _repeat[key] = TimeSpan.Zero;
                        State[key].WasPressed = false;
                    }
                }
            }
            foreach (var state in State.Where(x => !x.Value.IsPressed && x.Value.WasPressed))
            {
                _repeat[state.Key] = TimeSpan.Zero;
            }
        }

        protected virtual IEnumerable<Buttons> RetrievePressedButtons(GamePadState gamePadState)
        {
            foreach (var key in State.Keys)
            {
                if (gamePadState.IsButtonDown(key))
                    yield return key;
            }
        }
    }
}