#include <epictuner/sdk/ui.hpp>
#include <string>
#include <thread>
#include <chrono>
#include <cstdlib>
#include <stdexcept>
#include <optional>

using namespace et::sdk;
class HelloPanels : public Plugin {
    Ui ui_;
    std::optional<Context> context_;
    et_async_options completion_{sizeof(et_async_options), ET_OPERATION_TIMEOUT_MS, 0, 0, this, completed};
    static void ET_CALL completed(void* owner, const et_completion* result) noexcept {
        // Completion callbacks must never throw across compiler/allocator boundaries.
        auto* self = static_cast<HelloPanels*>(owner);
        if (result->code != ET_OK && result->code != ET_ERROR_CANCELLED)
            self->context_->log("hello UI request rejected", ET_LOG_ERROR);
    }
    static et_result ET_CALL event(void* owner, const et_ui_event* event) { static_cast<HelloPanels*>(owner)->onUi(*event); return ET_OK; }
    void onUi(const et_ui_event& e) {
        const std::string_view node(e.node.data ? e.node.data : "", e.node.size);
        if (e.type == ET_UI_CLOSE_REQUEST) {
#ifdef ET_HELLO_TEST_FAULTS
            const std::string_view definition(e.definition.data, e.definition.size);
            if (definition.ends_with(".ignore-close")) return;
#endif
            ui_.action(e.panel, ET_UI_ALLOW_CLOSE, e.origin, &completion_); return;
        }
        if (e.type != ET_UI_CLICK) return;
        if (node == "greet") ui_.patch(e.panel, {Ui::text("status", ET_UI_TITLE, "Hello from the compiled C++ worker!")}, e.revision, e.origin, &completion_);
        else if (node == "float") ui_.open("org.epictuner.examples.hello.inspector", "A", ET_PLACEMENT_FLOATING, &completion_);
        else if (node == "second") ui_.open("org.epictuner.examples.hello.inspector", "B", ET_PLACEMENT_FLOATING, &completion_);
        else if (node == "modal") ui_.open("org.epictuner.examples.hello.dialog", {}, ET_PLACEMENT_MODAL, &completion_);
        else if (node == "dismiss") ui_.action(e.panel, ET_UI_CLOSE, 0, &completion_);
    }
public:
    static constexpr std::string_view id = "org.epictuner.examples.hello";
    static constexpr uint64_t capabilities = ET_CAP_UI | ET_CAP_LOG | ET_CAP_EVENTS;
    et_result start(Context& context) {
        context_.emplace(context);
        auto result = ui_.connect(context, event, this); if (result != ET_OK) return result;
        PanelBuilder p("org.epictuner.examples.hello.main", "Hello panels");
        p.definition.flags |= ET_PANEL_DIRTY_CLOSE;
        p.definition.menu = p.keep("Examples/Hello panels");
        p.add(ET_UI_COLUMN, "root").text(ET_UI_TITLE, "Native plugin · ET controls");
        p.add(ET_UI_BANNER, "intro", "root").text(ET_UI_TITLE, "Built with the public C++ SDK. Edit values, switch tabs, and open independent instances.");
        p.add(ET_UI_FORM, "form", "root");
        p.add(ET_UI_TEXT, "name", "form").text(ET_UI_TITLE, "Name").text(ET_UI_VALUE, "EpicTuner").boolean(ET_UI_PERSIST, true).text(ET_UI_TOOLTIP, "Enter commits; Escape restores the last valid value.");
        p.add(ET_UI_NUMBER, "target", "form").text(ET_UI_TITLE, "Target lambda").number(ET_UI_MINIMUM, 0.65).number(ET_UI_MAXIMUM, 1.2).number(ET_UI_VALUE, 0.95).number(ET_UI_DECIMALS, 2).text(ET_UI_UNITS, "λ").boolean(ET_UI_PERSIST, true);
        p.add(ET_UI_SELECT, "mode", "form").text(ET_UI_TITLE, "Mode").text(ET_UI_OPTIONS, "Street\nTrack\nEconomy").number(ET_UI_VALUE, 0).boolean(ET_UI_PERSIST, true);
        p.add(ET_UI_CHECKBOX, "enabled", "root").text(ET_UI_TITLE, "Enable greeting").boolean(ET_UI_VALUE, true).boolean(ET_UI_PERSIST, true);
        p.add(ET_UI_ROW, "actions", "root");
        p.add(ET_UI_BUTTON, "greet", "actions").text(ET_UI_TITLE, "Say hello").text(ET_UI_BIND_ENABLED, "enabled");
        p.add(ET_UI_BUTTON, "float", "actions").text(ET_UI_TITLE, "Inspector A");
        p.add(ET_UI_BUTTON, "second", "actions").text(ET_UI_TITLE, "Inspector B");
        p.add(ET_UI_BUTTON, "modal", "actions").text(ET_UI_TITLE, "Open dialog");
        p.add(ET_UI_LABEL, "status", "root").text(ET_UI_TITLE, "Ready for your greeting.");
        p.add(ET_UI_TABS, "tabs", "root").number(ET_UI_VALUE, 0).boolean(ET_UI_PERSIST, true);
        p.add(ET_UI_SECTION, "settings", "tabs").text(ET_UI_TITLE, "Bindings");
        p.add(ET_UI_TEXT, "mirror", "settings").text(ET_UI_TITLE, "Shared name").text(ET_UI_BIND_VALUE, "name").boolean(ET_UI_TWO_WAY, true);
        p.add(ET_UI_SLIDER, "level", "settings").number(ET_UI_VALUE, 35).boolean(ET_UI_PERSIST, true);
        p.add(ET_UI_PROGRESS, "progress", "settings").number(ET_UI_VALUE, 0.65);
        p.add(ET_UI_SECTION, "results", "tabs").text(ET_UI_TITLE, "Results");
        p.add(ET_UI_TABLE, "table", "results").text(ET_UI_TITLE, "Analysis").text(ET_UI_OPTIONS, "RPM\nLambda").text(ET_UI_DATA, "1000\t0.98\n2000\t0.96\n3000\t0.95");
        p.add(ET_UI_CHART, "chart", "results").text(ET_UI_DATA, "1\n3\n2\n6\n4\n7\n5");
        p.add(ET_UI_SECTION, "gallery", "tabs").text(ET_UI_TITLE, "Controls");
        p.add(ET_UI_IMAGE, "logo", "gallery").text(ET_UI_SOURCE, "assets/epictuner.png").number(ET_UI_PREFERRED_HEIGHT, 60);
        p.add(ET_UI_GRID, "grid", "gallery").number(ET_UI_COLUMNS, 2);
        p.add(ET_UI_SWITCH, "switch", "grid").text(ET_UI_TITLE, "Show details").boolean(ET_UI_VALUE, true).boolean(ET_UI_PERSIST, true);
        p.add(ET_UI_LABEL, "detail", "grid").text(ET_UI_TITLE, "Visibility follows the switch.").text(ET_UI_BIND_VISIBLE, "switch");
        p.add(ET_UI_SEPARATOR, "separator", "gallery");
        p.add(ET_UI_TREE, "tree", "gallery").text(ET_UI_TITLE, "Channels").text(ET_UI_DATA, "Engine\n\tRPM\n\tLoad\nSensors\n\tLambda\n\tTemperature");
        p.add(ET_UI_SCROLL, "scroll", "gallery").number(ET_UI_PREFERRED_HEIGHT, 90);
        p.add(ET_UI_LIST, "list", "scroll").text(ET_UI_TITLE, "Samples").text(ET_UI_DATA, "First\nSecond\nThird\nFourth\nFifth\nSixth");
        result = ui_.define(p, &completion_); if (result != ET_OK) return result;
        PanelBuilder inspector("org.epictuner.examples.hello.inspector", "Inspector");
        inspector.definition.flags = ET_PANEL_MULTIPLE | ET_PANEL_PERSIST;
        inspector.definition.menu = inspector.keep("");
        inspector.definition.placements = ET_PLACEMENT_FLOATING | ET_PLACEMENT_WORKSPACE;
        inspector.add(ET_UI_COLUMN, "root").text(ET_UI_TITLE, "Independent panel state");
        inspector.add(ET_UI_TEXT, "note", "root").text(ET_UI_TITLE, "Instance note").text(ET_UI_VALUE, "Edit this instance").boolean(ET_UI_PERSIST, true);
        inspector.add(ET_UI_SPLITTER, "split", "root").number(ET_UI_VALUE, 0.5).boolean(ET_UI_PERSIST, true);
        inspector.add(ET_UI_SECTION, "left", "split").text(ET_UI_TITLE, "Left");
        inspector.add(ET_UI_LABEL, "leftLabel", "left").text(ET_UI_TITLE, "Drag the splitter.");
        inspector.add(ET_UI_SECTION, "right", "split").text(ET_UI_TITLE, "Right");
        inspector.add(ET_UI_LABEL, "rightLabel", "right").text(ET_UI_TITLE, "Placement and state restore.");
        result = ui_.define(inspector, &completion_); if (result != ET_OK) return result;
        PanelBuilder dialog("org.epictuner.examples.hello.dialog", "Plugin dialog");
        dialog.definition.placements = ET_PLACEMENT_MODAL; dialog.definition.flags = ET_PANEL_DIRTY_CLOSE;
        dialog.definition.menu = dialog.keep(""); dialog.definition.width = 480; dialog.definition.height = 300;
        dialog.add(ET_UI_COLUMN, "root");
        dialog.add(ET_UI_BANNER, "message", "root").text(ET_UI_TITLE, "This parent-modal ET window closes asynchronously. A failed worker cannot trap you here.");
        dialog.add(ET_UI_TEXT, "answer", "root").text(ET_UI_TITLE, "Answer");
        dialog.add(ET_UI_BUTTON, "dismiss", "root").text(ET_UI_TITLE, "Done");
        return ui_.define(dialog, &completion_);
    }
    et_result onEvent(const et_event& e) {
        // Explicit development fault commands used by the acceptance harness.
        const std::string_view text(e.text.data, e.text.size);
#ifdef ET_HELLO_TEST_FAULTS
        if (text == "crash") std::abort();
        if (text == "hang") std::this_thread::sleep_for(std::chrono::seconds(20));
#endif
        return ET_OK;
    }
};
ET_PLUGIN(HelloPanels)
