using System.Diagnostics;
using XInputDotNetPure;

namespace Assets.Scripts.GamepadInterface
{
    //Uses XInputDotNet - https://github.com/speps/XInputDotNet

    public static class Controller
    {
        private static Gamepad _controller;

        //return first active controller only. 
        public static PlayerIndex? FindController()
        {
            _controller = new Gamepad();    //Hold the item in memory

            for (var i = 0; i < 4; ++i)
            {
                var state = GamePad.GetState((PlayerIndex)i);
                if (!state.IsConnected) continue;

                return (PlayerIndex)i;
            }
            return null;
        }

        //Search for all active controllers
        public static PlayerIndex[] FindControllers()
        {
            _controller = new Gamepad();            //Not sure this is a good idea. Maybe Gamepad[4] would work better. 
            var result = new PlayerIndex[4];
            for (var i = 0; i < 4; ++i)
            {
                result[i] = (PlayerIndex) i;
            }
            return result;
        }

        public static Gamepad GetState(PlayerIndex player)
        {
            return _controller.UpdateState(player);
        }
    }

    public class Gamepad
    {
        public bool IsConnected;
        public Stick Left;
        public Stick Right;
        public DPad Dpad;
        public Button A;
        public Button B;
        public Button X;
        public Button Y;
        public Button Back;
        public Button Start;
        public Button LeftBumper;
        public Button RightBumper;
        public Button Home;     //This doesnt work, intercepted by Windows.
        public Trigger LeftTrigger;
        public Trigger RightTrigger;

        private GamePadState _state;
        private GamePadState _prevState;

        public Gamepad UpdateState(PlayerIndex player)
        {
            _prevState = _state;
            _state = GamePad.GetState(player);
            IsConnected = _state.IsConnected;
            if (!IsConnected) return this;

            Left = new Stick(_state.ThumbSticks.Left, _state.Buttons.LeftStick, _prevState.Buttons.LeftStick);
            Right = new Stick(_state.ThumbSticks.Right, _state.Buttons.RightStick, _prevState.Buttons.RightStick);
            Dpad = new DPad(_state.DPad, _prevState.DPad);
            A = new Button(_state.Buttons.A, _prevState.Buttons.A);
            B = new Button(_state.Buttons.B, _prevState.Buttons.B);
            X = new Button(_state.Buttons.X, _prevState.Buttons.X);
            Y = new Button(_state.Buttons.Y, _prevState.Buttons.Y);
            Back = new Button(_state.Buttons.Back, _prevState.Buttons.Back);
            Start = new Button(_state.Buttons.Start, _prevState.Buttons.Start);
            LeftBumper = new Button(_state.Buttons.LeftShoulder, _prevState.Buttons.LeftShoulder);
            RightBumper = new Button(_state.Buttons.RightShoulder, _prevState.Buttons.RightShoulder);
            LeftTrigger = new Trigger(_state.Triggers.Left);
            RightTrigger = new Trigger(_state.Triggers.Right);
            //Home = new Button(_state.Buttons.Guide, _prevState.Buttons.Guide);

            return this;
        }

        //0 - 1
        public void SetRumble(PlayerIndex player, float left, float right)
        {
            GamePad.SetVibration(player, left, right);
        }

        //Definitions
        public struct Trigger
        {
            public Trigger(float value)
            {
                Value = value;
            }

            public float Value;
        }

        public struct Button
        {
            public Button(ButtonState state, ButtonState oldState)
            {
                Hold = state == ButtonState.Pressed;
                Down = (state == ButtonState.Pressed && oldState == ButtonState.Released);
                Up = (state == ButtonState.Released && oldState == ButtonState.Pressed);
            }

            public bool Down;
            public bool Hold;
            public bool Up;
        }

        public struct DPad
        {
            public Button Up;
            public Button Down;
            public Button Left;
            public Button Right;

            public DPad(GamePadDPad state, GamePadDPad prevState)
            {
                Up = new Button(state.Up, prevState.Up);
                Down = new Button(state.Down, prevState.Down);
                Left = new Button(state.Left, prevState.Left);
                Right = new Button(state.Right, prevState.Right);
            }
        }

        public struct Stick
        {
            public float X;
            public float Y;
            public Button Click;

            public Stick(GamePadThumbSticks.StickValue state, ButtonState clickState, ButtonState prevClickState)
            {
                X = state.X;
                Y = state.Y;
                Click = new Button(clickState, prevClickState);
            }
        }
    }
}
