// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

package org.wpilib.driverstation;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.wpilib.hardware.hal.HAL;
import org.wpilib.simulation.NiDsPS5ControllerSim;

class NiDsPS5ControllerTest {
  @ParameterizedTest
  @EnumSource(value = NiDsPS5Controller.Button.class)
  void testButtons(NiDsPS5Controller.Button button)
      throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    HAL.initialize(500, 0);
    NiDsPS5Controller joy = new NiDsPS5Controller(2);
    NiDsPS5ControllerSim joysim = new NiDsPS5ControllerSim(joy);

    var buttonName = button.toString();

    String simSetMethodName = "set" + buttonName;
    String joyGetMethodName = "get" + buttonName;
    String joyPressedMethodName = "get" + buttonName + "Pressed";
    String joyReleasedMethodName = "get" + buttonName + "Released";

    final Method simSetMethod = joysim.getClass().getMethod(simSetMethodName, boolean.class);
    final Method joyGetMethod = joy.getClass().getMethod(joyGetMethodName);
    final Method joyPressedMethod = joy.getClass().getMethod(joyPressedMethodName);
    final Method joyReleasedMethod = joy.getClass().getMethod(joyReleasedMethodName);

    simSetMethod.invoke(joysim, false);
    joysim.notifyNewData();
    assertFalse((Boolean) joyGetMethod.invoke(joy));
    // need to call pressed and released to clear flags
    joyPressedMethod.invoke(joy);
    joyReleasedMethod.invoke(joy);

    simSetMethod.invoke(joysim, true);
    joysim.notifyNewData();
    assertTrue((Boolean) joyGetMethod.invoke(joy));
    assertTrue((Boolean) joyPressedMethod.invoke(joy));
    assertFalse((Boolean) joyReleasedMethod.invoke(joy));

    simSetMethod.invoke(joysim, false);
    joysim.notifyNewData();
    assertFalse((Boolean) joyGetMethod.invoke(joy));
    assertFalse((Boolean) joyPressedMethod.invoke(joy));
    assertTrue((Boolean) joyReleasedMethod.invoke(joy));
  }

  @ParameterizedTest
  @EnumSource(value = NiDsPS5Controller.Axis.class)
  void testAxes(NiDsPS5Controller.Axis axis)
      throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    HAL.initialize(500, 0);
    NiDsPS5Controller joy = new NiDsPS5Controller(2);
    NiDsPS5ControllerSim joysim = new NiDsPS5ControllerSim(joy);

    var axisName = axis.toString();

    String simSetMethodName = "set" + axisName;
    String joyGetMethodName = "get" + axisName;

    Method simSetMethod = joysim.getClass().getMethod(simSetMethodName, double.class);
    Method joyGetMethod = joy.getClass().getMethod(joyGetMethodName);

    simSetMethod.invoke(joysim, 0.35);
    joysim.notifyNewData();
    assertEquals(0.35, (Double) joyGetMethod.invoke(joy), 0.001);
  }
}
