/**
 * The LED effects influenced by dice rolls.
 */
#pragma once

#include "wled.h"

#include "dice_state.h"

// Reuse FX display functions.
extern void mode_breath();
extern void mode_blends();
extern void mode_glitter();
extern void mode_gravcenter();

static constexpr uint8_t USER_ANY_DIE = 0xFF;
/**
 * Two custom effect parameters are used.
 * c1 - Source Die. Sets which die from [0 - MAX_NUM_DICE) controls this effect.
 *      If this is set to 0xFF, use the latest event regardless of which die it
 *      came from.
 * c2 - Target Roll. Sets the "success" criteria for a roll to >= this value.
 */

/**
 * Return the last die roll based on the custom1 effect setting.
 */
static pixels::RollEvent GetLastRollForSegment() {
  // If an invalid die is selected, fallback to using the most recent roll from
  // any die.
  if (SEGMENT.custom1 >= MAX_NUM_DICE) {
    return GetLastRoll();
  } else {
    return last_die_events[SEGMENT.custom1];
  }
}


/*
 * Alternating pixels running function (copied static function).
 */
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
#define PALETTE_SOLID_WRAP   (paletteBlend == 1 || paletteBlend == 3)
static void running_copy(uint32_t color1, uint32_t color2, bool theatre = false) {
  int width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4);  // window
  uint32_t cycleTime = 50 + (255 - SEGMENT.speed);
  uint32_t it = strip.now / cycleTime;
  bool usePalette = color1 == SEGCOLOR(0);

  for (int i = 0; i < SEGLEN; i++) {
    uint32_t col = color2;
    if (usePalette) color1 = SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0);
    if (theatre) {
      if ((i % width) == SEGENV.aux0) col = color1;
    } else {
      int pos = (i % (width<<1));
      if ((pos < SEGENV.aux0-width) || ((pos >= SEGENV.aux0) && (pos < SEGENV.aux0+width))) col = color1;
    }
    SEGMENT.setPixelColor(i,col);
  }

  if (it != SEGENV.step) {
    SEGENV.aux0 = (SEGENV.aux0 +1) % (theatre ? width : (width<<1));
    SEGENV.step = it;
  }
}

static void simple_roll() {
  auto roll = GetLastRollForSegment();
  if (roll.state != pixels::RollState::ON_FACE) {
    SEGMENT.fill(0);
  } else {
    uint16_t num_segments = float(roll.current_face + 1) / 20.0 * SEGLEN;
    for (int i = 0; i <= num_segments; i++) {
      SEGMENT.setPixelColor(i, SEGCOLOR(0));
    }
    for (int i = num_segments; i < SEGLEN; i++) {
      SEGMENT.setPixelColor(i, SEGCOLOR(1));
    }
  }
}
// See https://kno.wled.ge/interfaces/json-api/#effect-metadata
// Name - DieSimple
// Parameters -
//   * Selected Die (custom1)
// Colors - Uses color1 and color2
// Palette - Not used
// Flags - Effect is optimized for use on 1D LED strips.
// Defaults - Selected Die set to 0xFF (USER_ANY_DIE)
static const char _data_FX_MODE_SIMPLE_DIE[] PROGMEM =
    "DieSimple@,,Selected Die;!,!;;1;c1=255";

static void pulse_roll() {
  auto roll = GetLastRollForSegment();
  if (roll.state != pixels::RollState::ON_FACE) {
    mode_breath();
    return;
  } else {
    mode_blends();
    uint16_t num_segments = float(roll.current_face + 1) / 20.0 * SEGLEN;
    for (int i = num_segments; i < SEGLEN; i++) {
      SEGMENT.setPixelColor(i, SEGCOLOR(1));
    }
  }
}
static const char _data_FX_MODE_PULSE_DIE[] PROGMEM =
    "DiePulse@!,!,Selected Die;!,!;!;1;sx=24,pal=50,c1=255";

static void check_roll() {
  auto roll = GetLastRollForSegment();
  if (roll.state != pixels::RollState::ON_FACE) {
    running_copy(SEGCOLOR(0), SEGCOLOR(2));
    return;
  } else {
    if (roll.current_face + 1 >= SEGMENT.custom2) {
      mode_glitter();
      return;
    } else {
      mode_gravcenter();
      return;
    }
  }
}
static const char _data_FX_MODE_CHECK_DIE[] PROGMEM =
    "DieCheck@!,!,Selected Die,Target Roll;1,2,3;!;1;pal=0,ix=128,m12=2,si=0,c1=255,c2=10";
