#include "sseg.h"
#include <esp_log.h>
#include "state_tracking.h"
#include <cstring>

TM1640* sseg = nullptr;

static const char *TAG = "sseg";

static bool replay_handler(const char* event, char* arg) {
    if (strcmp(event, "SSEG_G_RAW") == 0) {
        uint8_t segments[4];
        segments[0] = atoi(strtok(arg, ","));
        for (int i = 1; i < 4; i++) {
            segments[i] = atoi(strtok(NULL, ","));
        }
        set_game_sseg_raw(segments);
        return true;
    }
    if (strcmp(event, "SSEG_G_CLR") == 0) {
        clear_game_sseg();
        return true;
    }
    if (strcmp(event, "SSEG_M_RAW") == 0) {
        uint8_t segments[4];
        segments[0] = atoi(strtok(arg, ","));
        for (int i = 1; i < 4; i++) {
            segments[i] = atoi(strtok(NULL, ","));
        }
        set_module_sseg_raw(segments);
        return true;
    }
    if (strcmp(event, "SSEG_M_CLR") == 0) {
        clear_module_sseg();
        return true;
    }
    if (strcmp(event, "SSEG_G") == 0) {
        uint32_t value = atoi(strtok(arg, ","));
        uint8_t dot_pos = atoi(strtok(NULL, ","));
        set_game_sseg_num(value, dot_pos);
        return true;
    }
     if (strcmp(event, "SSEG_M") == 0) {
        uint32_t value = atoi(strtok(arg, ","));
        uint8_t dot_pos = atoi(strtok(NULL, ","));
        set_module_sseg_num(value, dot_pos);
        return true;
    }

    return false;
}

void init_sseg() {
    ESP_LOGI(TAG, "Initializing sseg...");

    sseg = new TM1640(SSEG_PIN_DATA, SSEG_PIN_CLK, 8);

    register_replay_fn(replay_handler);

    ESP_LOGI(TAG, "Sseg initialized!");
}

void set_game_sseg_raw(const uint8_t* segments) {
    sseg->setSegments(segments[0], 0);
    sseg->setSegments(segments[1], 1);
    sseg->setSegments(segments[2], 2);
    sseg->setSegments(segments[3], 3);

    if (is_state_tracking()) {
        char buf[32];
        sprintf(buf, "%d,%d,%d,%d", segments[0], segments[1], segments[2], segments[3]);
        event_occured("SSEG_G_RAW", buf);
    }
}
void clear_game_sseg() {
    sseg->setSegments(0, 0);
    sseg->setSegments(0, 1);
    sseg->setSegments(0, 2);
    sseg->setSegments(0, 3);

    if (is_state_tracking()) {
        event_occured("SSEG_G_CLR", NULL);
    }
}

void set_module_sseg_raw(const uint8_t* segments) {
    sseg->setSegments(segments[0], 4);
    sseg->setSegments(segments[1], 5);
    sseg->setSegments(segments[2], 6);
    sseg->setSegments(segments[3], 7);

    if (is_state_tracking()) {
        char buf[32];
        sprintf(buf, "%d,%d,%d,%d", segments[0], segments[1], segments[2], segments[3]);
        event_occured("SSEG_M_RAW", buf);
    }
}

void clear_module_sseg() {
    sseg->setSegments(0, 4);
    sseg->setSegments(0, 5);
    sseg->setSegments(0, 6);
    sseg->setSegments(0, 7);

    if (is_state_tracking()) {
        event_occured("SSEG_M_CLR", NULL);
    }
}

void set_game_sseg_num(uint32_t value, uint8_t dot_pos) {
    uint32_t initial_value = value;
    for (int i = 0; i < 4; i++) {
        auto idx = value % 10;
        sseg->sendChar(3-i, TM16XX_NUMBER_FONT[idx], i == dot_pos);
        value = value / 10;
    }

    if (is_state_tracking()) {
        char buf[16];
        sprintf(buf, "%ld,%d", initial_value, dot_pos);
        event_occured("SSEG_G", buf);
    }
}

void set_module_sseg_num(uint32_t value, uint8_t dot_pos) {
    uint32_t initial_value = value;
    for (int i = 0; i < 4; i++) {
        auto idx = value % 10;
        sseg->sendChar(7-i, TM16XX_NUMBER_FONT[idx], i == dot_pos);
        value = value / 10;
    }

    if (is_state_tracking()) {
        char buf[16];
        sprintf(buf, "%ld,%d", initial_value, dot_pos);
        event_occured("SSEG_M", buf);
    }
}
