using System;
using System.Collections.Generic;
using System.Linq;

namespace Igdc.Controls
{
    public abstract class ControlConfigBase
    {
        public float VibrateLeft, VibrateRight;

        public FieldCell FieldCell { get; }
        public abstract ControlState ExitButton { get; }
        public abstract ControlState FullscreenButton { get; }
        public abstract ControlState RestartButton { get; }
        public abstract ControlState BattleLeftButton { get; }
        public abstract ControlState BattleRightButton { get; }
        public abstract ControlState MoveLeftButton { get; }
        public abstract ControlState MoveUpButton { get; }
        public abstract ControlState MoveRightButton { get; }
        public abstract ControlState MoveDownButton { get; }
        public abstract ControlState MagicButton { get; }
        public abstract ControlState UiNextButton { get; }
        public abstract ControlState UiPrevButton { get; }
        public abstract ControlState UiAcceptButton { get; }
        protected abstract ControlState GetFieldCell(int x, int y);

        public virtual void Refresh()
        {
            VibrateLeft *= 0.9f;
            VibrateRight *= 0.9f;
        }

        public void Feedback(float? left, float? right)
        {
            if (left.HasValue) VibrateLeft = left.Value;
            if (right.HasValue) VibrateRight = right.Value;
        }

        public ControlConfigBase()
        {
            FieldCell = new FieldCell((x, y) => GetFieldCell(x, y));
        }
    }

    public abstract class ControlConfigBase<T> : ControlConfigBase
    {
        private Dictionary<T, int> _dict = new Dictionary<T, int>();

        protected abstract bool CheckButton(T button);

        protected ControlState ProcessButton(params T[] buttons)
        {
            var key = buttons.First();
            var isPressed = buttons.Any(b => CheckButton(b));
            _dict.TryGetValue(key, out var framesPressed);
            if (isPressed) _dict[key] = framesPressed + 1;
            else _dict[key] = 0;
            if (framesPressed > IgdcGame.Current.ButtonTimeout * 2)
            {
                _dict[key] = 0;
                return ControlState.None;
            }
            if (isPressed && framesPressed > IgdcGame.Current.ButtonTimeout) return ControlState.None;
            var wasPressed = framesPressed > 0;
            return wasPressed && isPressed ? ControlState.Hold
                : wasPressed && !isPressed ? ControlState.Release
                : !wasPressed && isPressed ? ControlState.Press
                : ControlState.None;
        }
    }

    public class FieldCell
    {
        private Func<int, int, ControlState> _func;

        public ControlState this[int x, int y] => _func(x, y);

        public FieldCell(Func<int, int, ControlState> func)
        {
            _func = func;
        }
    }

    public enum ControlState
    {
        None, Press, Hold, Release
    }

    public static class ControlStateExt
    {
        public static bool Holding(this ControlState state) => state == ControlState.Hold || Pressed(state);
        public static bool Pressed(this ControlState state) => state == ControlState.Press;
        public static bool Released(this ControlState state) => state == ControlState.Release;
    }
}