#define private public
#include "emc/rs274ngc/rs274ngc_interp.hh"
#undef private

#include <cstdlib>
#include <filesystem>
#include <iostream>
#include <unistd.h>

#include "canon_event_sink.hh"
#include "linuxcnc_tool_adapter.hh"
#include "nml_intf/emc.hh"

namespace {

std::filesystem::path make_temp_dir()
{
    std::string pattern = "/tmp/linuxcnc-init-XXXXXX";
    char *path = mkdtemp(pattern.data());
    if (path == nullptr) {
        std::perror("mkdtemp");
        std::exit(2);
    }
    return path;
}

}  // namespace

int main()
{
    const auto temp_dir = make_temp_dir();
    std::filesystem::current_path(temp_dir);

    emcStatus->motion.traj.linearUnits = 1.0;
    standalone::reset_tool_adapter();
    Interp interp;
    standalone::reset_canon_events();

    const int rc = interp.init();
    std::cout << "init=" << rc << "\n";
    std::cout << "setup.length_units=" << static_cast<int>(interp._setup.length_units) << "\n";
    std::cout << "setup.origin_index=" << interp._setup.origin_index << "\n";
    std::cout << "setup.distance_mode=" << static_cast<int>(interp._setup.distance_mode) << "\n";
    std::cout << "setup.feed_mode=" << static_cast<int>(interp._setup.feed_mode) << "\n";
    std::cout << "setup.motion_mode=" << interp._setup.motion_mode << "\n";
    std::cout << "canon_event_count=" << standalone::canon_events().size() << "\n";
    for (const auto &event : standalone::canon_events()) {
        std::cout << "canon_event=" << event << "\n";
    }

    emcStatus->motion.traj.linearUnits = 1.0 / 25.4;
    standalone::reset_tool_adapter();
    Interp inch_interp;
    standalone::reset_canon_events();
    const int inch_rc = inch_interp.init();
    std::cout << "inch_init=" << inch_rc << "\n";
    std::cout << "inch_setup.length_units="
              << static_cast<int>(inch_interp._setup.length_units) << "\n";
    std::cout << "inch_external_length_units="
              << GET_EXTERNAL_LENGTH_UNITS() << "\n";
    std::cout << "inch_canon_event_count=" << standalone::canon_events().size() << "\n";
    for (const auto &event : standalone::canon_events()) {
        std::cout << "inch_canon_event=" << event << "\n";
    }

    standalone::reset_tool_adapter();
    CANON_TOOL_TABLE tool = standalone::tool_entry_init();
    tool.toolno = 2;
    tool.pocketno = 2;
    standalone::set_tool_entry(2, tool);
    standalone::select_tool(2);
    standalone::change_selected_tool();

    Interp synch_interp;
    const int synch_rc = synch_interp.synch();
    std::cout << "synch=" << synch_rc << "\n";
    std::cout << "synch.current_pocket=" << synch_interp._setup.current_pocket << "\n";
    std::cout << "synch.selected_pocket=" << synch_interp._setup.selected_pocket << "\n";
    std::cout << "synch.tool_0=" << synch_interp._setup.tool_table[0].toolno << "\n";
    std::cout << "synch.tool_2=" << synch_interp._setup.tool_table[2].toolno << "\n";

    emcStatus->motion.traj.linearUnits = 1.0;
    standalone::reset_tool_adapter();
    std::filesystem::remove_all(temp_dir);
    return (rc == INTERP_OK && inch_rc == INTERP_OK && synch_rc == INTERP_OK) ? 0 : 1;
}
