#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "bio/bio.h"
#include "bio_product.h"

static void print_usage(void) {
    puts("Bio-Digital native runner");
    puts("Usage:");
    puts("  bio --version");
    puts("  bio variant <kernel>");
    puts("  bio ingest <model.gguf> --out <model.bdst> --delta <model.bdl>");
    puts("  bio learn <model.bdst> [--seconds N] [--checkpoint-sec N] [--profile nrl-daemon|hybrid|nrl-fast|nrl-max|nrl-edge|nrl-sweet|nrl-100k|cpu-quality] [--target-steps N] [--cap-bytes N]");
    puts("  bio chat <model.bdst> [--prompt \"...\"] [--max-tokens N] [--idle-learn-after-sec N]");
    puts("  bio serve <model.bdst> [--max-tokens N] [--idle-learn-after-sec N] [--checkpoint-sec N] [--profile nrl-daemon|hybrid|nrl-fast|nrl-max|nrl-edge|nrl-sweet|nrl-100k|cpu-quality] [--cap-bytes N]");
    puts("  bio run <file.bio>");
    puts("  bio <file.bio>");
}

static const char *arg_value(int argc, char **argv, const char *name,
                             const char *fallback) {
    for (int i = 0; i + 1 < argc; ++i) {
        if (strcmp(argv[i], name) == 0) {
            return argv[i + 1];
        }
    }
    return fallback;
}

static unsigned arg_u32(int argc, char **argv, const char *name, unsigned fallback) {
    const char *s = arg_value(argc, argv, name, NULL);
    return s == NULL ? fallback : (unsigned)strtoul(s, NULL, 10);
}

static uint64_t arg_u64(int argc, char **argv, const char *name, uint64_t fallback) {
    const char *s = arg_value(argc, argv, name, NULL);
    return s == NULL ? fallback : (uint64_t)strtoull(s, NULL, 10);
}

int main(int argc, char **argv) {
    bio_v1_status rc = BIO_OK;

    if (argc < 2) {
        print_usage();
        return 1;
    }

    rc = bio_v1_init();
    if (rc != BIO_OK) {
        fprintf(stderr, "bio: init failed rc=%d\n", (int)rc);
        return (int)rc;
    }

    if (strcmp(argv[1], "--version") == 0) {
        puts(bio_v1_version());
        return 0;
    }

    if (strcmp(argv[1], "variant") == 0) {
        if (argc < 3) {
            print_usage();
            return 1;
        }
        puts(bio_v1_active_variant(argv[2]));
        return 0;
    }

    if (strcmp(argv[1], "ingest") == 0) {
        const char *out = arg_value(argc, argv, "--out", "model.bdst");
        const char *delta = arg_value(argc, argv, "--delta", "model.bdl");
        if (argc < 3) {
            print_usage();
            return 1;
        }
        rc = bio_product_ingest(argv[2], out, delta);
        return rc == BIO_OK ? 0 : (int)rc;
    }

    if (strcmp(argv[1], "learn") == 0) {
        if (argc < 3) {
            print_usage();
            return 1;
        }
        rc = bio_product_learn(argv[2], arg_u32(argc, argv, "--seconds", 5u),
                               arg_u32(argc, argv, "--checkpoint-sec", 5u),
                               arg_value(argc, argv, "--profile", "hybrid"),
                               arg_u64(argc, argv, "--target-steps", 0u),
                               arg_u64(argc, argv, "--cap-bytes", 1099511627776ull));
        return rc == BIO_OK ? 0 : (int)rc;
    }

    if (strcmp(argv[1], "chat") == 0) {
        if (argc < 3) {
            print_usage();
            return 1;
        }
        rc = bio_product_chat(argv[2], arg_value(argc, argv, "--prompt", "hi"),
                              arg_u32(argc, argv, "--max-tokens", 64u),
                              arg_u32(argc, argv, "--idle-learn-after-sec", 60u));
        return rc == BIO_OK ? 0 : (int)rc;
    }

    if (strcmp(argv[1], "serve") == 0) {
        if (argc < 3) {
            print_usage();
            return 1;
        }
        rc = bio_product_serve(argv[2], arg_u32(argc, argv, "--max-tokens", 64u),
                               arg_u32(argc, argv, "--idle-learn-after-sec", 60u),
                               arg_u32(argc, argv, "--checkpoint-sec", 60u),
                               arg_value(argc, argv, "--profile", "hybrid"),
                               arg_u64(argc, argv, "--cap-bytes", 1099511627776ull));
        return rc == BIO_OK ? 0 : (int)rc;
    }

    if (strcmp(argv[1], "run") == 0) {
        if (argc < 3) {
            print_usage();
            return 1;
        }
        rc = bio_v1_run_file(argv[2]);
        return rc == BIO_OK ? 0 : (int)rc;
    }

    rc = bio_v1_run_file(argv[1]);
    return rc == BIO_OK ? 0 : (int)rc;
}
