//
// Created by mark on 6/6/25.
//

#include <ReportsAndCharts/WChartJSOptions.h>
#include <Wt/Json/Value.h>

// --- Nested Structs toJsonObject() Implementations ---

WChartJSOptions::WChartJSOptions(ChartJSType type) : chartType_(type), devicePixelRatio_(0) {}


Wt::Json::Object WChartJSOptions::LegendOptions::toJsonObject() const {
    Wt::Json::Object obj;
    if (display) {
        obj["display"] = Wt::Json::Value(display);
        obj["position"] = Wt::Json::Value(position);
        if (reverse) {
            obj["reverse"] = Wt::Json::Value(reverse);
        }
    }
    return obj;
}

Wt::Json::Object WChartJSOptions::TitleOptions::toJsonObject() const {
    Wt::Json::Object obj;
    if (display) {
        obj["display"] = Wt::Json::Value(display);
        obj["text"] = Wt::Json::Value(text);
        obj["position"] = Wt::Json::Value(position);
        obj["font"] = Wt::Json::Object{{"size", Wt::Json::Value(fontSize)}};
    }
    return obj;
}

Wt::Json::Object WChartJSOptions::TooltipOptions::toJsonObject() const {
    Wt::Json::Object obj;
    if (enabled) {
        obj["enabled"] = Wt::Json::Value(enabled);
        obj["mode"] = Wt::Json::Value(mode);
        obj["intersect"] = Wt::Json::Value(intersect);
        if (reverse) { // <-- ADD THIS BLOCK
            obj["reverse"] = Wt::Json::Value(reverse);
        }
        if (!freeFormOptions.empty()) { // <-- Add this block
            obj.insert(freeFormOptions.begin(), freeFormOptions.end());
        }
    }
    return obj;
}

Wt::Json::Object WChartJSOptions::ZoomAndPanOptions::toJsonObject() const {
    Wt::Json::Object zoomAndPanObj;
    if (enabled) {
        Wt::Json::Object enabledTrue;
        Wt::Json::Object zoomOptions;
        Wt::Json::Object panOptions;
        Wt::Json::Object zoomObj;
        Wt::Json::Object panObj;
        enabledTrue["enabled"] = Wt::Json::Value(true);

        if (wheelEnabled)
            zoomOptions["wheel"] = Wt::Json::Value(enabledTrue);
        if (pinchEnabled)
            zoomOptions["pinch"] = Wt::Json::Value(enabledTrue);
        zoomOptions["mode"] = Wt::Json::Value(mode);

        if (panEnabled)
            panOptions["enabled"] = Wt::Json::Value(true);

        panOptions["mode"] = Wt::Json::Value(mode);

        zoomAndPanObj["pan"] = Wt::Json::Value(panOptions);
        zoomAndPanObj["zoom"] = Wt::Json::Value(zoomOptions);
    }
    return zoomAndPanObj;
}

Wt::Json::Object WChartJSOptions::PluginOptions::toJsonObject() const {
    Wt::Json::Object obj;
    obj["legend"] = legend.toJsonObject();
    obj["title"] = title.toJsonObject();
    obj["tooltip"] = tooltip.toJsonObject();
    obj["zoom"] = zoomAndPan.toJsonObject();
    return obj;
}

Wt::Json::Object WChartJSOptions::TickOptions::toJsonObject() const {
    Wt::Json::Object obj;

    // Explicitly output the boolean, whether true or false
    obj["display"] = Wt::Json::Value(display);

    if (!color.empty()) {
        obj["color"] = Wt::Json::Value(color);
    }
    if (autoSkip) {
        obj["autoSkip"] = Wt::Json::Value(autoSkip);
    }
    // Free form options must always be evaluated, independent of the display flag
    if (!freeFormOptions.empty()) {
        obj.insert(freeFormOptions.begin(), freeFormOptions.end());
    }

    return obj;
}

Wt::Json::Object WChartJSOptions::ScaleTitleOptions::toJsonObject() const {
    Wt::Json::Object obj;
    if (display) {
        obj["display"] = Wt::Json::Value(display);
        obj["text"] = Wt::Json::Value(text);
    }
    return obj;
}

Wt::Json::Object WChartJSOptions::GridOptions::toJsonObject() const {
    Wt::Json::Object obj;

    // Explicitly output the boolean, whether true or false
    obj["display"] = Wt::Json::Value(display);

    if (!color.empty()) {
        obj["color"] = Wt::Json::Value(color);
    }
    if (!freeFormOptions.empty()) {
        obj.insert(freeFormOptions.begin(), freeFormOptions.end());
    }

    return obj;
}

Wt::Json::Object WChartJSOptions::AxisOptions::toJsonObject() const {
    Wt::Json::Object obj = freeFormOptions;
    obj["display"] = Wt::Json::Value(display);
    obj["type"] = Wt::Json::Value(type);
    obj["stacked"] = Wt::Json::Value(stacked);
    obj["ticks"] = ticks.toJsonObject();
    obj["title"] = title.toJsonObject();
    obj["grid"] = grid.toJsonObject();
    return obj;
}

Wt::Json::Object WChartJSOptions::ScalesOptions::toJsonObject() const {
    Wt::Json::Object obj;
    if (axisOptions.display) obj[axisOptions.axis] = axisOptions.toJsonObject();
    return obj;
}

Wt::Json::Object WChartJSOptions::LayoutOptions::toJsonObject() const {
    Wt::Json::Object obj;
    if (std::holds_alternative<int>(padding)) {
        obj["padding"] = Wt::Json::Value(std::get<int>(padding));
    } else if (std::holds_alternative<Wt::Json::Object>(padding)) {
        obj["padding"] = std::get<Wt::Json::Object>(padding);
    }
    return obj;
}

Wt::Json::Object WChartJSOptions::InteractionOptions::toJsonObject() const {
    Wt::Json::Object obj;
    obj["mode"] = Wt::Json::Value(mode);
    obj["intersect"] = Wt::Json::Value(intersect);
    obj["axis"] = Wt::Json::Value(axis);
    return obj;
}


// --- Main Options Class Method Implementations ---

void WChartJSOptions::setResponsive(bool isResponsive) {
    responsive_ = isResponsive;
    options_["responsive"] = Wt::Json::Value(responsive_);
    options_["onResize"] = Wt::Json::Value("handleResize");
}

void WChartJSOptions::setMaintainAspectRatio(bool maintain) {
    maintainAspectRatio_ = maintain;
    options_["maintainAspectRatio"] = Wt::Json::Value(maintainAspectRatio_);
}

void WChartJSOptions::setAspectRatio(double ratio) {
    aspectRatio_ = ratio;
    options_["aspectRatio"] = Wt::Json::Value(aspectRatio_);
}

void WChartJSOptions::setDevicePixelRatio(int ratio) {
    devicePixelRatio_ = ratio;
    options_["devicePixelRatio"] = Wt::Json::Value(devicePixelRatio_);
}

void WChartJSOptions::setLocale(const std::string& locale) {
    locale_ = locale;
    options_["locale"] = Wt::Json::Value(locale_);
}

void WChartJSOptions::setIndexAxis(const std::string& axis) {
    options_["indexAxis"] = Wt::Json::Value(axis);
}

void WChartJSOptions::setPlugins(const PluginOptions& plugins) {
    plugins_ = plugins;
    options_["plugins"] = plugins_.toJsonObject();
}

void WChartJSOptions::setXScales(const ScalesOptions& scales) {
    Wt::Json::Object scalesObj;
    // Check if scales already exist (e.g., from setYScales)
    if (options_.find("scales") != options_.end()) {
        scalesObj = options_.get("scales");
    }

    if (scales.axisOptions.display) {
        // Force the object key to "x"
        scalesObj["x"] = scales.axisOptions.toJsonObject();
    }
    options_["scales"] = scalesObj;
}

void WChartJSOptions::setYScales(const ScalesOptions& scales) {
    Wt::Json::Object scalesObj;
    // Check if scales already exist (e.g., from setXScales)
    if (options_.find("scales") != options_.end()) {
        scalesObj = options_.get("scales");
    }

    if (scales.axisOptions.display) {
        // Force the object key to "y"
        scalesObj["y"] = scales.axisOptions.toJsonObject();
    }
    options_["scales"] = scalesObj;
}
void WChartJSOptions::setRScales(const ScalesOptions& scales) {
    scales_ = scales;
    options_["scales"] = scales_.toJsonObject();
}

void WChartJSOptions::setLayout(const LayoutOptions& layout) {
    layout_ = layout;
    // The layout object might be empty, so we reconstruct it
    Wt::Json::Object layoutObj = layout.toJsonObject();
    if (!layoutObj.empty()) {
        options_["layout"] = layoutObj;
    }
}

void WChartJSOptions::setInteraction(const InteractionOptions& interaction) {
    interaction_ = interaction;
    options_["interaction"] = interaction_.toJsonObject();
}

const Wt::Json::Object& WChartJSOptions::getOptions() const {
    return options_;
}
