/******************************************************************************
*
* Copyright (C) 2026  Brian Berlin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
#define SDL_DISABLE_OLD_NAMES
#include <SDL3/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

#include "../src/interface/katconfig.h"

static int failure = 0;

static void output_result(int result, const char *test, const char *value,
        const char *error)
{
    if (result) {
        printf("[PASS] %s Result=%s\n", test, value);
    }
    else {
        ++failure;
        printf("[FAIL] %s %s Result=%s\n", test, error, value);
    }
}

static int make_temp_filename(char *filename, size_t size)
{
#ifdef _WIN32
    char *result = tmpnam(filename);
    (void) size;
    return result ? 0 : -1;
#else
    int fd;

    if (snprintf(filename, size, "/tmp/kat_ui_input_XXXXXX") >= (int) size)
        return -1;

    fd = mkstemp(filename);
    if (fd < 0)
        return -1;

    close(fd);
    return 0;
#endif
}

static int write_initial_config(const char *filename)
{
    FILE *fp = fopen(filename, "wb");

    if (!fp)
        return -1;

    fputs("[input.misc]\n", fp);
    fputs("back = [ \"enable|key|escape|press\" ]\n", fp);
    fclose(fp);

    return 0;
}

static int read_file_text(const char *filename, char *buffer, size_t buffer_size)
{
    FILE *fp = fopen(filename, "rb");
    size_t bytes;

    if (!fp)
        return 0;

    bytes = fread(buffer, 1, buffer_size - 1, fp);
    fclose(fp);

    buffer[bytes] = '\0';

    return 1;
}

static void set_controller_button_input(t_input_common *input, int device_num,
        int button)
{
    memset(input, 0, sizeof(*input));
    input->enable = 1;
    input->device[0] = DEV_CONTROLLER;
    input->device_num[0] = device_num;
    input->part_type[0] = PART_TYPE_BUTTON;
    input->part_num[0] = button;
    input->direction[0] = DIR_PRESS;
}

static void test_ui_back_save_writes_and_reloads(void)
{
    char filename[64];
    char file_text[2048];
    int wrote_binding;
    t_toml_node *tbl;
    t_config *cfg = config_get_global_cfg();

    if (make_temp_filename(filename, sizeof(filename)) ||
            write_initial_config(filename)) {
        output_result(0, "UI Back Save Temp File", filename,
                "Could not create temp config");
        return;
    }

    tbl = toml_parse_file(filename);
    if (!tbl) {
        output_result(0, "UI Back Save Parse", filename,
                "Could not parse temp config");
        remove(filename);
        return;
    }

    set_controller_button_input(&cfg->input.ui.back, 2,
            SDL_GAMEPAD_BUTTON_EAST);
    config_save_ui_input(tbl, KCFG_UI_BACK);
    toml_free_node_tree(tbl);

    if (!read_file_text(filename, file_text, sizeof(file_text)))
        strcpy(file_text, "Could not read saved config");

    wrote_binding = strstr(file_text, "enable|c2|b_b|press") != NULL;
    output_result(wrote_binding,
            "UI Back Save Writes File", wrote_binding ? filename : file_text,
            "Missing saved controller B binding");

    memset(&cfg->input.ui.back, 0, sizeof(cfg->input.ui.back));
    tbl = toml_parse_file(filename);
    if (!tbl) {
        output_result(0, "UI Back Reload Parse", filename,
                "Could not parse saved config");
        remove(filename);
        return;
    }

    config_load_ui_input(tbl);
    toml_free_node_tree(tbl);

    output_result(cfg->input.ui.back.enable &&
            cfg->input.ui.back.device[0] == DEV_CONTROLLER &&
            cfg->input.ui.back.device_num[0] == 2 &&
            cfg->input.ui.back.part_type[0] == PART_TYPE_BUTTON &&
            cfg->input.ui.back.part_num[0] == SDL_GAMEPAD_BUTTON_EAST &&
            cfg->input.ui.back.direction[0] == DIR_PRESS,
            "UI Back Save Reloads", "GamePad:2 B",
            "Reloaded binding did not match saved controller");

    remove(filename);
}

int main(void)
{
    test_ui_back_save_writes_and_reloads();

    return failure;
}
