/* tests.c - Unit test sederhana tanpa framework eksternal */
#include <stdio.h>
#include <string.h>

#include "inventory.h"
#include "storage.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_product_create_valid(void) {
    Product p;
    int rc = product_create(&p, 1, "Beras 5kg", 65000.0, 20);
    ASSERT(rc == 0, "product_create valid harus sukses");
    ASSERT(p.id == 1, "id harus 1");
    ASSERT(strcmp(p.name, "Beras 5kg") == 0, "nama harus sesuai");
    ASSERT(p.price == 65000.0, "harga harus sesuai");
    ASSERT(p.stock == 20, "stok harus 20");
    ASSERT(product_is_valid(&p), "produk harus valid");
}

static void test_product_create_invalid(void) {
    Product p;
    ASSERT(product_create(&p, 0, "X", 1.0, 1) != 0, "id=0 harus ditolak");
    ASSERT(product_create(&p, 1, "", 1.0, 1) != 0, "nama kosong ditolak");
    ASSERT(product_create(&p, 1, "X", -1.0, 1) != 0, "harga negatif ditolak");
    ASSERT(product_create(&p, 1, "X", 1.0, -5) != 0, "stok negatif ditolak");
}

static void test_inventory_add_and_find(void) {
    Inventory inv;
    inventory_init(&inv);
    int id1 = inventory_add(&inv, "Beras", 65000.0, 10);
    int id2 = inventory_add(&inv, "Gula", 15000.0, 5);
    ASSERT(id1 == 1, "id produk pertama harus 1");
    ASSERT(id2 == 2, "id produk kedua harus 2");
    ASSERT(inv.count == 2, "jumlah harus 2");

    Product *p = inventory_find_by_id(&inv, 2);
    ASSERT(p != NULL, "id=2 harus ditemukan");
    ASSERT(strcmp(p->name, "Gula") == 0, "nama produk id=2 harus Gula");

    ASSERT(inventory_find_by_id(&inv, 999) == NULL, "id tidak ada = NULL");
}

static void test_inventory_find_name(void) {
    Inventory inv;
    inventory_init(&inv);
    inventory_add(&inv, "Beras Premium", 80000.0, 5);
    inventory_add(&inv, "Gula Pasir", 15000.0, 5);
    inventory_add(&inv, "Beras Merah", 75000.0, 3);

    Product out[16];
    int n = inventory_find_by_name(&inv, "beras", out, 16);
    ASSERT(n == 2, "pencarian 'beras' case-insensitive harus 2");

    n = inventory_find_by_name(&inv, "X", out, 16);
    ASSERT(n == 0, "pencarian tanpa match harus 0");
}

static void test_inventory_update_delete(void) {
    Inventory inv;
    inventory_init(&inv);
    int id = inventory_add(&inv, "Teh", 12000.0, 8);
    ASSERT(inventory_update(&inv, id, 13000.0, 10) == 0, "update harus sukses");
    Product *p = inventory_find_by_id(&inv, id);
    ASSERT(p->price == 13000.0, "harga harus 13000");
    ASSERT(p->stock == 10, "stok harus 10");

    ASSERT(inventory_update(&inv, id, -1.0, 0) != 0, "harga negatif ditolak");
    ASSERT(inventory_delete(&inv, id) == 0, "delete harus sukses");
    ASSERT(inv.count == 0, "jumlah harus 0 setelah delete");
    ASSERT(inventory_delete(&inv, id) != 0, "delete ulang harus gagal");
}

static void test_inventory_sort(void) {
    Inventory inv;
    inventory_init(&inv);
    inventory_add(&inv, "Chiki", 5000.0, 10);
    inventory_add(&inv, "Apel", 8000.0, 5);
    inventory_add(&inv, "Bola", 3000.0, 7);

    inventory_sort_by_name(&inv);
    ASSERT(strcmp(inv.items[0].name, "Apel") == 0, "sort nama [0] = Apel");
    ASSERT(strcmp(inv.items[1].name, "Bola") == 0, "sort nama [1] = Bola");
    ASSERT(strcmp(inv.items[2].name, "Chiki") == 0, "sort nama [2] = Chiki");

    inventory_sort_by_price(&inv);
    ASSERT(inv.items[0].price == 3000.0, "sort harga [0] = 3000");
    ASSERT(inv.items[2].price == 8000.0, "sort harga [2] = 8000");
}

static void test_storage_roundtrip(void) {
    Inventory inv;
    inventory_init(&inv);
    inventory_add(&inv, "Beras", 65000.0, 10);
    inventory_add(&inv, "Gula", 15000.0, 5);

    const char *path = "/tmp/test_inventory.csv";
    int written = storage_save(&inv, path);
    ASSERT(written == 2, "harus menulis 2 baris");

    Inventory loaded;
    int read = storage_load(&loaded, path);
    ASSERT(read == 2, "harus membaca 2 baris");
    ASSERT(loaded.count == 2, "count harus 2 setelah load");
    ASSERT(strcmp(loaded.items[0].name, "Beras") == 0, "nama[0] = Beras");
    ASSERT(loaded.next_id == 3, "next_id harus 3 setelah load");
}

int main(void) {
    test_product_create_valid();
    test_product_create_invalid();
    test_inventory_add_and_find();
    test_inventory_find_name();
    test_inventory_update_delete();
    test_inventory_sort();
    test_storage_roundtrip();

    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;
}
