// Mission 2 · Mustaflash : le ruban de LEDs aux commandes de la manette
// Chaque bouton lance un scénario lumineux sur 10 LEDs du ruban WS2812B.
// Flèches : luminosité et vitesse. R2 : les réacteurs s'emballent.
// Joystick droit : la couleur suit sa direction.

#include <Bluepad32.h>
#include <FastLED.h>

// ================= Réglages =================
#define PIN_RUBAN  5             // le fil de données (DIN), via la résistance de 330 Ω
#define NB_LEDS    10            // on ne commande que les 10 premières LEDs
const int LUM_MAX = 120;         // plafond de luminosité (sur 255) : l'USB ne suivrait pas plus
const int MILLIAMPERES_MAX = 400;// FastLED baisse tout seul la luminosité au-delà de ce courant

CRGB leds[NB_LEDS];              // une case par LED : sa couleur
ControllerPtr manette = nullptr;

// ================= Les scénarios =================
// 0 éteint, 1 réacteur, 2 alerte, 3 hyperespace, 4 arc-en-ciel
const int NB_SCENARIOS = 5;
const char* NOMS[NB_SCENARIOS] = {"éteint", "réacteur", "alerte rouge", "hyperespace", "arc-en-ciel"};
int scenario = 0;
int luminosite = 40;             // de 5 à LUM_MAX
int vitesse = 100;               // en % : 100 = normal
unsigned long horloge = 0;       // horloge des animations (avance selon la vitesse)
unsigned long dernierTemps = 0;

// ================= Mémoire des boutons =================
enum { B_CROIX, B_ROND, B_TRIANGLE, B_CARRE, B_R1, B_HAUT, B_BAS, B_GAUCHE, B_DROITE, NB_BOUTONS };
bool avant[NB_BOUTONS];

bool vientDAppuyer(int numero, bool appuye) {   // vrai seulement au moment de l'appui
  bool nouveau = appuye && !avant[numero];
  avant[numero] = appuye;
  return nouveau;
}

// ================= Connexion de la manette =================
void onConnectedController(ControllerPtr ctl) {
  if (manette != nullptr) return;               // une seule manette à la fois
  manette = ctl;
  ctl->setColorLED(0, 0, 255);
  Serial.println("🎮 Manette connectée : à toi de jouer !");
}

void onDisconnectedController(ControllerPtr ctl) {
  if (manette == ctl) {
    manette = nullptr;
    scenario = 0;                               // par prudence, on éteint le ruban
    Serial.println("❌ Manette déconnectée : ruban éteint");
  }
}

void choisir(int s, uint8_t r, uint8_t g, uint8_t b) {
  scenario = s;
  manette->setColorLED(r, g, b);                // la barre lumineuse prend la couleur du scénario
  Serial.printf("Scénario : %s\n", NOMS[s]);
}

// ================= Lecture de la manette =================
void lireManette() {
  if (vientDAppuyer(B_CROIX,    manette->a()))  choisir(1, 0, 80, 255);    // réacteur bleu
  if (vientDAppuyer(B_ROND,     manette->b()))  choisir(2, 255, 0, 0);     // alerte rouge
  if (vientDAppuyer(B_TRIANGLE, manette->y()))  choisir(3, 255, 255, 255); // hyperespace
  if (vientDAppuyer(B_CARRE,    manette->x()))  choisir(4, 0, 255, 0);     // arc-en-ciel
  if (vientDAppuyer(B_R1,       manette->r1())) choisir(0, 20, 20, 20);    // extinction

  uint8_t f = manette->dpad();
  if (vientDAppuyer(B_HAUT, f & DPAD_UP)) {
    luminosite = min(luminosite + 10, LUM_MAX);
    Serial.printf("Luminosité : %d / %d\n", luminosite, LUM_MAX);
  }
  if (vientDAppuyer(B_BAS, f & DPAD_DOWN)) {
    luminosite = max(luminosite - 10, 5);
    Serial.printf("Luminosité : %d / %d\n", luminosite, LUM_MAX);
  }
  if (vientDAppuyer(B_DROITE, f & DPAD_RIGHT)) {
    vitesse = min(vitesse + 25, 400);
    Serial.printf("Vitesse : %d %%\n", vitesse);
  }
  if (vientDAppuyer(B_GAUCHE, f & DPAD_LEFT)) {
    vitesse = max(vitesse - 25, 25);
    Serial.printf("Vitesse : %d %%\n", vitesse);
  }
}

// ================= Les animations =================
void reacteur(unsigned long t) {
  int boost = manette ? manette->throttle() / 4 : 0;          // R2 : 0 à 255
  unsigned long bpm = 30 + boost / 4;                         // battements par minute : R2 accélère
  uint8_t phase = t * bpm * 256UL / 60000UL;                  // où on en est dans le battement
  uint8_t base = 40 + scale8(sin8(phase), 215);               // pulsation douce entre 40 et 255
  fill_solid(leds, NB_LEDS, CRGB(boost / 3, boost / 3, base)); // bleu, qui blanchit avec R2
}

void alerte(unsigned long t) {
  bool phase = (t / 300) % 2;                                 // change toutes les 300 ms
  for (int i = 0; i < NB_LEDS; i++) {
    bool gauche = i < NB_LEDS / 2;
    leds[i] = (gauche == phase) ? CRGB::Red : CRGB::Black;    // une moitié, puis l'autre
  }
}

void hyperespace(unsigned long t) {
  fadeToBlackBy(leds, NB_LEDS, 60);                           // la traînée s'efface doucement
  int pos = (t / 60) % NB_LEDS;                               // le point avance d'une LED / 60 ms
  leds[pos] = CRGB::White;
}

void arcEnCiel(unsigned long t) {
  fill_rainbow(leds, NB_LEDS, t / 10, 255 / NB_LEDS);         // tout l'arc-en-ciel, qui défile
}

void couleurJoystick(int rx, int ry) {
  int angle = atan2(-ry, rx) * 180 / PI;                      // direction du joystick droit
  uint8_t teinte = (angle + 360) % 360 * 255 / 360;           // de 0 à 255 pour FastLED
  fill_solid(leds, NB_LEDS, CHSV(teinte, 255, 255));
}

void afficher() {
  unsigned long maintenant = millis();
  horloge += (maintenant - dernierTemps) * vitesse / 100;
  dernierTemps = maintenant;

  int rx = manette ? manette->axisRX() : 0;
  int ry = manette ? manette->axisRY() : 0;
  if (abs(rx) > 200 || abs(ry) > 200) {
    couleurJoystick(rx, ry);                                  // le joystick droit a la priorité
  } else {
    switch (scenario) {
      case 0: fill_solid(leds, NB_LEDS, CRGB::Black); break;
      case 1: reacteur(horloge); break;
      case 2: alerte(horloge); break;
      case 3: hyperespace(horloge); break;
      case 4: arcEnCiel(horloge); break;
    }
  }
  FastLED.setBrightness(luminosite);
  FastLED.show();                                             // on envoie tout au ruban
}

// ================= Programme principal =================
void setup() {
  Serial.begin(115200);
  FastLED.addLeds<WS2812B, PIN_RUBAN, GRB>(leds, NB_LEDS);
  FastLED.setMaxPowerInVoltsAndMilliamps(5, MILLIAMPERES_MAX);
  FastLED.setBrightness(luminosite);
  fill_solid(leds, NB_LEDS, CRGB::Black);
  FastLED.show();

  BP32.setup(&onConnectedController, &onDisconnectedController);
  BP32.forgetBluetoothKeys();   // à mettre en commentaire une fois que tout marche
  Serial.println("Mustaflash prêt. Maintiens SHARE + PS pour coupler la manette.");
}

void loop() {
  BP32.update();
  if (manette && manette->isConnected()) lireManette();
  afficher();
  delay(10);
}
