#include "ctools/libft/printf/ft_printf.h"
#include "ctools/printf/ft_printf.h"
#include <stdint.h>
#include <string.h>
#include <gpiod.h>
#include <errno.h>
#include <unistd.h>

#define GPIO_CHIP_NAME "gpiochip0"
#define GPIO_CHIP_PATH "/dev/"GPIO_CHIP_NAME

#define FAIL(code, msg, ...) \
    do { \
        ft_fprintf(STDERR_FILENO, msg, ##__VA_ARGS__); \
        exit(code); \
    } while (0);

#define DIGIT_ONE 17
#define DIGIT_TWO 22
#define DIGIT_THREE 26
#define DIGIT_FOUR 24

#define SER 7
#define RCLK 5
#define SRCLK 6

int main() {
    struct gpiod_chip *chip;
    struct gpiod_line_request *request;
    struct gpiod_line_settings *settings;
    struct gpiod_line_config *line_cfg;
    struct gpiod_request_config *req_cfg;
    uint32_t lines[] = {DIGIT_ONE, DIGIT_TWO, DIGIT_THREE, DIGIT_FOUR, SER, SRCLK, RCLK};

    uint32_t digits[] = { DIGIT_ONE, DIGIT_TWO, DIGIT_THREE, DIGIT_FOUR };

    // Open chip
    chip = gpiod_chip_open("/dev/gpiochip0");

    // Create line settings for output
    settings = gpiod_line_settings_new();
    gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_OUTPUT);
    gpiod_line_settings_set_output_value(settings, GPIOD_LINE_VALUE_INACTIVE);

    // Create line config and add our line
    line_cfg = gpiod_line_config_new();

    gpiod_line_config_add_line_settings(line_cfg, lines, 2, settings);

    // Create request config
    req_cfg = gpiod_request_config_new();
    gpiod_request_config_set_consumer(req_cfg, "my_program");

    // Request the line
    request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);

    gpiod_line_request_set_value(request, SRCLK, GPIOD_LINE_VALUE_INACTIVE);
    gpiod_line_request_set_value(request, RCLK, GPIOD_LINE_VALUE_INACTIVE);
    while (1) {
        for (uint32_t i = 0; i < 4; i++) {
            gpiod_line_request_set_value(request, digits[i], GPIOD_LINE_VALUE_ACTIVE);
            for (uint32_t j = 0; j < 7; j++) {
                gpiod_line_request_set_value(request, SRCLK, GPIOD_LINE_VALUE_INACTIVE);
                gpiod_line_request_set_value(request, SER, GPIOD_LINE_VALUE_INACTIVE);
                gpiod_line_request_set_value(request, SRCLK, GPIOD_LINE_VALUE_ACTIVE);
                usleep(50);
            }
            usleep(100);
            gpiod_line_request_set_value(request, RCLK, GPIOD_LINE_VALUE_ACTIVE);
            usleep(100);
            gpiod_line_request_set_value(request, RCLK, GPIOD_LINE_VALUE_INACTIVE);
            gpiod_line_request_set_value(request, digits[i], GPIOD_LINE_VALUE_INACTIVE);
            usleep(1); // 500ms
        }
    }

    // Cleanup
    gpiod_line_request_release(request);
    gpiod_line_config_free(line_cfg);
    gpiod_line_settings_free(settings);
    gpiod_request_config_free(req_cfg);
    gpiod_chip_close(chip);

    return 0;
}
