// build_gallery — build an actor embedding gallery from a directory of images
//
// Gallery directory layout:
//   gallery_root/
//     nm0000093_Brad_Pitt/
//       img1.jpg
//       img2.jpg
//     nm0000129_Cate_Blanchett/
//       ...
//
// Usage:
//   build_gallery --root <gallery_root> --output <gallery.json> [options]
//
// Options:
//   --detector <path>   SCRFD detector model (default: models/scrfd_500m_bnkps.onnx)
//   --arcface <path>    ArcFace model (default: models/arcface_w600k_r50.onnx)
//   --conf <f>          face detection confidence threshold (default: 0.5)
//   --nms <f>           NMS IoU threshold (default: 0.4)

#include "gallery/gallery_builder.hpp"
#include "gallery/gallery_report.hpp"
#include "gallery/gallery_calibration.hpp"
#include "gallery/gallery_store.hpp"
#include "config.hpp"

#include <cstring>
#include <iostream>
#include <stdexcept>
#include <string>

int main(int argc, char** argv) {
    std::string root_path, output_path;
    std::string detector_model = kDefaultDetectorModel;
    std::string arcface_model  = kDefaultArcfaceModel;
    float conf = 0.5f, nms_thr = 0.4f;
    int   max_side = 500;
    float min_face_px = 0.f;

    for (int i = 1; i < argc; ++i) {
        auto arg  = [&](const char* f) { return std::strcmp(argv[i], f) == 0; };
        auto next = [&]() -> std::string {
            if (++i >= argc)
                throw std::runtime_error(std::string("missing arg after ") + argv[i-1]);
            return argv[i];
        };
        try {
            if      (arg("--root"))      root_path      = next();
            else if (arg("--output"))    output_path    = next();
            else if (arg("--detector"))  detector_model = next();
            else if (arg("--arcface"))   arcface_model  = next();
            else if (arg("--conf"))      conf           = std::stof(next());
            else if (arg("--nms"))       nms_thr        = std::stof(next());
            else if (arg("--max-side"))  max_side       = std::stoi(next());
            else if (arg("--min-face-px")) min_face_px = std::stof(next());
            else { std::cerr << "[warn] unknown flag: " << argv[i] << "\n"; }
        } catch (const std::exception& e) {
            std::cerr << "Error: " << e.what() << "\n";
            return 1;
        }
    }

    if (root_path.empty() || output_path.empty()) {
        std::cerr << "Usage: build_gallery --root <dir> --output <gallery.json> "
                     "[--detector <path>] [--arcface <path>] [--max-side <N>]\n"
                     "       [--min-face-px <px>]\n";
        return 1;
    }

    BuildConfig cfg;
    cfg.gallery_root   = root_path;
    cfg.detector_model = detector_model;
    cfg.arcface_model  = arcface_model;
    cfg.detector_conf  = conf;
    cfg.detector_nms   = nms_thr;
    cfg.max_side       = max_side;
    cfg.min_face_px    = min_face_px;

    try {
        ActorGallery gallery = build_gallery(cfg);
        if (gallery.actors.empty()) {
            std::cerr << "No actors built — check your gallery directory.\n";
            return 1;
        }
        save_gallery(output_path, gallery);
        std::cerr << "Gallery saved to: " << output_path << "\n";

        /// TRACES: GR-003 | SR-001
        // Fit the calibration here and persist what it learned. The matcher
        // fits the same sigmoid at analysis time, but that is the wrong place
        // to audit a gallery from: by then the answer is per-run and nobody is
        // looking. Build time is when the gallery's quality is decided, and a
        // gallery can be quietly bad — heavily overlapping intra/inter
        // distributions, actors with no usable image — while looking fine.
        std::vector<Embedding> flat;
        std::vector<int>       flat_actor;
        for (int ai = 0; ai < static_cast<int>(gallery.actors.size()); ++ai)
            for (const auto& e : gallery.actors[ai].embeddings) {
                flat.push_back(e);
                flat_actor.push_back(ai);
            }

        GalleryCalibrationStats stats;
        GalleryCalibration cal = calibrate_gallery(flat, flat_actor, &stats);

        const GalleryReport report =
            build_gallery_report(gallery, cal, stats, nullptr, output_path);
        const std::string report_path = gallery_report_path(output_path);
        save_gallery_report(report_path, report);
        std::cerr << "Gallery report saved to: " << report_path << "\n";
    } catch (const std::exception& e) {
        std::cerr << "Fatal: " << e.what() << "\n";
        return 1;
    }
    return 0;
}
