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

#include "blobber/pipeline.h"
#include "blobber/dungeon.h"
#include "mesh/face_mesh.h"

static void usage(FILE *f, const char *prog) {
    fprintf(f,
        "usage: %s [options]\n"
        "\n"
        "Generates a 3D blobber dungeon (cell3d grid + per-material mesh).\n"
        "\n"
        "options:\n"
        "  --seed N            RNG seed (default 1234)\n"
        "  --levels N          number of stacked levels (default 1)\n"
        "  --depth N           dungeon depth bias, 1..26 (default 1)\n"
        "  --cell-size F       world size of one cell in meters (default 3.0)\n"
        "  --obj PATH          write an .obj dump of the mesh to PATH\n"
        "  --stats             print tri/cell stats to stderr (default on)\n"
        "  --quiet             suppress stats output\n"
        "  -h, --help          show this help and exit\n",
        prog);
}

int main(int argc, char **argv) {
    uint64_t seed = 1234;
    int n_levels = 1;
    int depth = 1;
    float cell_size = 3.0f;
    const char *obj_path = NULL;
    int want_stats = 1;

    for (int i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "--seed") && i + 1 < argc) {
            seed = strtoull(argv[++i], NULL, 10);
        } else if (!strcmp(argv[i], "--levels") && i + 1 < argc) {
            n_levels = atoi(argv[++i]);
            if (n_levels < 1) n_levels = 1;
        } else if (!strcmp(argv[i], "--depth") && i + 1 < argc) {
            depth = atoi(argv[++i]);
            if (depth < 1) depth = 1;
        } else if (!strcmp(argv[i], "--cell-size") && i + 1 < argc) {
            cell_size = (float)atof(argv[++i]);
        } else if (!strcmp(argv[i], "--obj") && i + 1 < argc) {
            obj_path = argv[++i];
        } else if (!strcmp(argv[i], "--stats")) {
            want_stats = 1;
        } else if (!strcmp(argv[i], "--quiet")) {
            want_stats = 0;
        } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
            usage(stdout, argv[0]);
            return 0;
        } else {
            fprintf(stderr, "unknown arg: %s\n", argv[i]);
            usage(stderr, argv[0]);
            return 2;
        }
    }

    dungeon_t *d = blobber_generate(seed, n_levels, depth);
    if (!d) {
        fprintf(stderr, "generation failed\n");
        return 1;
    }

    mesh_build_t *mb = mesh_build_from_dungeon(d, cell_size);
    if (!mb) {
        fprintf(stderr, "mesh build failed\n");
        dungeon_destroy(d);
        return 1;
    }

    if (obj_path) {
        if (!mesh_build_write_obj(mb, obj_path)) {
            fprintf(stderr, "could not write %s\n", obj_path);
            mesh_build_destroy(mb);
            dungeon_destroy(d);
            return 1;
        }
        fprintf(stderr, "wrote %s\n", obj_path);
    }

    if (want_stats) {
        size_t total_verts = 0, total_tris = 0;
        for (int m = 0; m < MAT_COUNT; m++) total_verts += mb->groups[m].vert_count;
        total_tris = total_verts / 3;
        int standable = 0;
        for (int lvl = 0; lvl < d->n_levels; lvl++) {
            for (int y = 0; y < BL_DROWS; y++) {
                for (int x = 0; x < BL_DCOLS; x++) {
                    if (b_floor_is_standable(dungeon_cell_c(d, lvl, x, y)->floor))
                        standable++;
                }
            }
        }
        fprintf(stderr,
                "seed=%llu levels=%d depth=%d cell=%.2f standable_cells=%d tris=%zu\n",
                (unsigned long long)seed, n_levels, depth, (double)cell_size,
                standable, total_tris);
        for (int m = 0; m < MAT_COUNT; m++) {
            if (mb->groups[m].vert_count == 0) continue;
            fprintf(stderr, "  mat %2d: %zu tris\n", m, mb->groups[m].vert_count / 3);
        }
    }

    mesh_build_destroy(mb);
    dungeon_destroy(d);
    return 0;
}
