#include "step2.h"

__attribute__((unused))
static const char *TAG = "step2";

static const int NUM_SOLVES = 4;

// one: 0b00000110
// seven: 0b00000111
static const uint8_t SSEG_NUMS[8] = {0b00111111, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b01111111, 0b01101111};
static const uint8_t SSEG_MAPS[5][4] = {
    {0b0101101, 0b1111010, 0b1000010, 0b1010100},
    {0b01000101, 0b00100100, 0b00110110, 0b01111011},
    {0b00101010, 0b00000010, 0b00010111, 0b00111100},
    {0b00111000, 0b01010010, 0b00101011, 0b00111010},
    {0b01000111, 0b00011001, 0b01111000, 0b00111110}
};

static const uint32_t INDICATOR_COLORS[5] = {
    LEDColor::LED_COLOR_RED,
    LEDColor::LED_COLOR_BLUE,
    LEDColor::LED_COLOR_GREEN,
    LEDColor::LED_COLOR_YELLOW,
    LEDColor::LED_COLOR_WHITE,
};

// random number generators
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<> answer_dist(0, 7);
static std::uniform_int_distribution<> map_dist(0, 4);
static std::uniform_int_distribution<> display_dist(0, 3);
static std::uniform_int_distribution<> random_segment_dist(0, 127);

static int answer = 0;
static uint8_t answer_sseg = SSEG_NUMS[0];
static char answer_char = '0';
static uint8_t display_map[4] = {0b00000000, 0b00000000, 0b00000000, 0b00000000};
static int chosen_map = 0;

std::map<int, int> number_map = {
    {0, 0},
    {1, 2},
    {2, 3},
    {3, 4},
    {4, 5},
    {5, 6},
    {6, 8},
    {7, 9},
};

static void new_puzzle(void) {
    // scramble lights
    for (int i = 0; i < 5; i++) {
        led_set(IndicatorLED::LED_SPEAKER, INDICATOR_COLORS[map_dist(gen)]);
        leds_flush();
        
        uint8_t random_segments[4] = {0, 0, 0, 0};
        for (int i = 0; i < 4; i++) {
            random_segments[i] = random_segment_dist(gen);
        }
        set_module_sseg_raw(random_segments);
        vTaskDelay(pdMS_TO_TICKS(100));
    }

    answer = answer_dist(gen);
    answer_sseg = SSEG_NUMS[answer];
    // convert answer to number value to account for missing 1 and 7
    answer = number_map[answer];
    answer_char = '0' + answer;
    // ESP_LOGI(TAG, "Answer: %i", answer);

    chosen_map = map_dist(gen);
    for (int i = 0; i < 4; ++i) {
        display_map[i] = SSEG_MAPS[chosen_map][i];
    }
    // ESP_LOGI(TAG, "Chosen Map: %i", chosen_map);

    led_set(IndicatorLED::LED_SPEAKER, INDICATOR_COLORS[chosen_map]);
    leds_flush();

    for (int i = 0; i < 8; i++) {
        bool bit = (answer_sseg >> i) & 1;
        if (bit == 1) {
            // choose display and flip bit
            int display = display_dist(gen);
            display_map[display] ^= (1 << i);
            // ESP_LOGI(TAG, "Flipping bit %i on display %i", i, display);
        }
    }
    set_module_sseg_raw(display_map);
}

void step2(void) {
    KeypadKey key;
    int solved_times = 0;

    new_puzzle();
    int strike_time = 0;
    while(solved_times < NUM_SOLVES) {
        // for every bit in the answer-
        if (get_keypad_pressed(&key)) {
            lcd_clear();
            char c = char_of_keypad_key(key);
            // ESP_LOGI(TAG, "Pressed: %c", c);
            if (c == answer_char) {
                solved_times++;
                if (solved_times < NUM_SOLVES) {
                    play_clip_wav(MOUNT_POINT "/partdone.wav", true, false, 0, 0);
                    clean_bomb();
                    new_puzzle();
                } else {
                    play_clip_wav(MOUNT_POINT "/stepdone.wav", true, false, 1, 0);
                    clear_module_sseg();
                }
            } else {
                strike_time = xTaskGetTickCount();
                strike("Incorrect Character!");
            }
        }

        if (strike_time != 0 && xTaskGetTickCount() - strike_time > pdMS_TO_TICKS(5000)) {
            strike_time = 0;
            lcd_clear();
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }

}
