/* tests.c - Unit test untuk CLI tool */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include "cli.h"
#include "config.h"
#include "file_processor.h"

static int tests_run = 0;
static int tests_pass = 0;

#define ASSERT(cond, msg) \
    do { \
        tests_run++; \
        if (cond) { \
            tests_pass++; \
        } else { \
            printf("FAIL: %s (line %d)\n", msg, __LINE__); \
        } \
    } while (0)

static void test_cli_parse_count(void) {
    char *argv[] = {"mtool", "count", "data.txt"};
    cli_args args;
    int rc = cli_parse(3, argv, &args);
    ASSERT(rc == 0, "count harus sukses");
    ASSERT(args.subcommand == CLI_SUB_COUNT, "subcommand = COUNT");
    ASSERT(args.file_path != NULL, "file_path = data.txt");
    ASSERT(strcmp(args.file_path, "data.txt") == 0, "file_path benar");
}

static void test_cli_parse_head_with_n(void) {
    char *argv[] = {"mtool", "head", "-n", "5", "data.txt"};
    cli_args args;
    int rc = cli_parse(5, argv, &args);
    ASSERT(rc == 0, "head -n 5 harus sukses");
    ASSERT(args.subcommand == CLI_SUB_HEAD, "subcommand = HEAD");
    ASSERT(args.count == 5, "count = 5");
}

static void test_cli_parse_grep(void) {
    char *argv[] = {"mtool", "grep", "hello", "-i", "data.txt"};
    cli_args args;
    int rc = cli_parse(5, argv, &args);
    ASSERT(rc == 0, "grep harus sukses");
    ASSERT(args.subcommand == CLI_SUB_GREP, "subcommand = GREP");
    ASSERT(strcmp(args.pattern, "hello") == 0, "pattern = hello");
    ASSERT(args.ignore_case == 1, "ignore_case = 1");
}

static void test_cli_parse_help_version(void) {
    char *argv1[] = {"mtool", "help"};
    cli_args args;
    ASSERT(cli_parse(2, argv1, &args) == 0, "help sukses");
    ASSERT(args.subcommand == CLI_SUB_HELP, "subcommand = HELP");

    char *argv2[] = {"mtool", "version"};
    ASSERT(cli_parse(2, argv2, &args) == 0, "version sukses");
    ASSERT(args.subcommand == CLI_SUB_VERSION, "subcommand = VERSION");

    char *argv3[] = {"mtool", "--help"};
    ASSERT(cli_parse(2, argv3, &args) == 0, "--help sukses");
    ASSERT(args.show_help == 1, "show_help = 1");
}

static void test_cli_parse_unknown_option(void) {
    char *argv[] = {"mtool", "head", "-Z"};
    cli_args args;
    int rc = cli_parse(3, argv, &args);
    ASSERT(rc == -1, "opsi tidak dikenal = error");
}

static void test_config_load(void) {
    const char *path = "/tmp/test_mtool.cfg";
    FILE *fp = fopen(path, "w");
    ASSERT(fp != NULL, "bisa membuat file config");
    fprintf(fp, "# komentar\n");
    fprintf(fp, "log_level = DEBUG\n");
    fprintf(fp, "default_count = 25\n");
    fprintf(fp, "; komentar titik koma\n");
    fprintf(fp, "name = mtool\n");
    fclose(fp);

    config c;
    int n = config_load(&c, path);
    ASSERT(n == 3, "harus ada 3 entri");

    const char *v = config_get(&c, "log_level");
    ASSERT(v != NULL && strcmp(v, "DEBUG") == 0, "log_level = DEBUG");

    int i = config_get_int(&c, "default_count", 10);
    ASSERT(i == 25, "default_count = 25");

    /* key tidak ada -> default */
    i = config_get_int(&c, "tidak_ada", 42);
    ASSERT(i == 42, "key tidak ada = default");
}

static void test_file_stats(void) {
    const char *path = "/tmp/test_mtool_data.txt";
    FILE *fp = fopen(path, "w");
    ASSERT(fp != NULL, "bisa membuat file data");
    fprintf(fp, "hello world\n");
    fprintf(fp, "second line here\n");
    fprintf(fp, "third\n");
    fclose(fp);

    file_stats s;
    int rc = file_stats_compute(path, &s);
    ASSERT(rc == 0, "stats harus sukses");
    ASSERT(s.lines == 3, "lines = 3");
    ASSERT(s.words == 6, "words = 6");
    ASSERT(s.chars > 0, "chars > 0");
}

static void test_file_head_tail(void) {
    const char *path = "/tmp/test_mtool_data.txt";
    /* File ini sudah dibuat di test sebelumnya. */

    /* Head 2 baris: kembalikan jumlah baris yang dicetak. */
    int n = file_head(path, 2);
    ASSERT(n == 2, "head harus cetak 2 baris");

    /* Head dengan n melebihi total baris: tetap OK, cetak semua. */
    n = file_head(path, 100);
    ASSERT(n == 3, "head 100 harus cetak 3 baris (semua)");

    n = file_tail(path, 1);
    ASSERT(n == 1, "tail 1 harus cetak 1 baris");

    n = file_tail(path, 100);
    ASSERT(n == 3, "tail 100 harus cetak 3 baris");
}

static void test_file_grep(void) {
    const char *path = "/tmp/test_mtool_data.txt";

    int n = file_grep(path, "line", 0);
    ASSERT(n == 1, "grep 'line' case-sensitive = 1 (second line here)");

    n = file_grep(path, "LINE", 0);
    ASSERT(n == 0, "grep 'LINE' case-sensitive = 0");

    n = file_grep(path, "LINE", 1);
    ASSERT(n == 1, "grep 'LINE' case-insensitive = 1");

    n = file_grep(path, "hello", 0);
    ASSERT(n == 1, "grep 'hello' = 1");
}

int main(void) {
    test_cli_parse_count();
    test_cli_parse_head_with_n();
    test_cli_parse_grep();
    test_cli_parse_help_version();
    test_cli_parse_unknown_option();
    test_config_load();
    test_file_stats();
    test_file_head_tail();
    test_file_grep();

    printf("\n=== Hasil Test ===\n");
    printf("Total : %d\n", tests_run);
    printf("Lulus : %d\n", tests_pass);
    printf("Gagal : %d\n", tests_run - tests_pass);
    return (tests_run == tests_pass) ? 0 : 1;
}
