#include "fgc/Application.h"
#include "fgc/Config.h"
#include "fgc/Logger.h"
#include "fgc/Paths.h"

#include <iostream>

#include <boost/program_options.hpp>

namespace po = boost::program_options;
using namespace fgc;

int main(int argc, char* argv[]) {
    po::options_description desc("Fire Gimbal Control options");
    desc.add_options()
        ("help,h", "show this help")
        ("config,c", po::value<std::string>(), "path to config.ini")
        ("init,i", po::bool_switch(), "run the endstop-finding init sequence")
        ("start,s", po::bool_switch(), "start capture automatically")
        ("demo,d", po::bool_switch(), "demo mode (copy placeholder image instead of encoding)")
        ("no-mqtt", po::bool_switch(), "disable MQTT (use a null control channel)")
        ("mock-camera", po::bool_switch(), "use a simulated camera (no hardware)")
        ("mock-serial", po::bool_switch(), "use a simulated motor controller (no hardware)")
        ("tui", po::bool_switch(), "show the full-screen terminal dashboard")
        ("no-tui", po::bool_switch(), "force the headless line console (overrides config)")
        ("log-level", po::value<std::string>(), "trace|debug|info|warn|error|off")
        ("trace", po::value<std::string>(),
         "verbatim wire trace, comma list: serial,mqtt,camera,control,all,none");

    po::variables_map vm;
    try {
        po::store(po::parse_command_line(argc, argv, desc), vm);
        po::notify(vm);
    } catch (const std::exception& e) {
        std::cerr << "Argument error: " << e.what() << "\n";
        return 1;
    }
    if (vm.count("help")) {
        std::cout << desc << "\n";
        return 0;
    }

    const std::string cli_cfg = vm.count("config") ? vm["config"].as<std::string>() : "";
    auto cfg_path = paths::resolveConfigPath(cli_cfg);
    if (!cfg_path) {
        std::cerr << "No config.ini found. Searched:\n";
        for (const auto& p : paths::configSearchPaths(cli_cfg)) std::cerr << "  - " << p << "\n";
        std::cerr << "Copy config/config.example.ini to one of these, pass --config, "
                     "or set $FGC_CONFIG.\n";
        return 1;
    }

    AppConfig cfg;
    try {
        cfg = ConfigLoader::loadFromFile(*cfg_path);
    } catch (const std::exception& e) {
        std::cerr << "Config error (" << *cfg_path << "): " << e.what() << "\n";
        return 1;
    }
    LOG_INFO << "Loaded config: " << *cfg_path;

    RuntimeOptions opts;
    opts.init  = vm["init"].as<bool>();
    opts.start = vm["start"].as<bool>();
    opts.demo  = vm["demo"].as<bool>();
    if (vm["no-mqtt"].as<bool>())     opts.use_mqtt    = false;
    if (vm["mock-camera"].as<bool>()) opts.mock_camera = true;
    if (vm["mock-serial"].as<bool>()) opts.mock_serial = true;
    if (vm["tui"].as<bool>())         opts.use_tui     = true;
    if (vm["no-tui"].as<bool>())      opts.use_tui     = false;  // --no-tui wins
    if (vm.count("log-level"))        opts.log_level   = vm["log-level"].as<std::string>();
    if (vm.count("trace"))            opts.trace_categories = vm["trace"].as<std::string>();
    opts.config_path = *cfg_path;  // so `gimbal calib` can offer to save back to it

    Application app(std::move(cfg), std::move(opts));
    return app.run();
}
