#include "io/PlanXmlWriter.h"
#include <wx/xml/xml.h>
#include <wx/string.h>

namespace MC {

static wxXmlNode* MakeNode(const wxString& name) {
    return new wxXmlNode(wxXML_ELEMENT_NODE, name);
}

static void Attr(wxXmlNode* node, const wxString& name, const wxString& value) {
    node->AddAttribute(name, value);
}

static void Attr(wxXmlNode* node, const wxString& name, int value) {
    node->AddAttribute(name, wxString::Format("%d", value));
}

bool PlanXmlWriter::Write(const RocrailPlan& plan, const std::string& filePath) {
    wxXmlDocument doc;
    doc.SetVersion("1.0");
    doc.SetFileEncoding("UTF-8");

    wxXmlNode* root = MakeNode("plan");
    Attr(root, "title", wxString::FromUTF8(plan.title));
    doc.SetRoot(root);

    // ── Tracks ──────────────────────────────────────────────────────────────
    for (const auto& tk : plan.tracks) {
        wxXmlNode* node = MakeNode("tk");
        Attr(node, "id",   wxString::FromUTF8(tk.id));
        Attr(node, "x",    tk.x);
        Attr(node, "y",    tk.y);
        Attr(node, "type", wxString::FromUTF8(tk.type));
        Attr(node, "ori",  wxString::FromUTF8(tk.ori));
        root->AddChild(node);
    }

    // ── Blocks ──────────────────────────────────────────────────────────────
    for (const auto& bk : plan.blocks) {
        wxXmlNode* node = MakeNode("bk");
        Attr(node, "id",  wxString::FromUTF8(bk.id));
        Attr(node, "x",   bk.x);
        Attr(node, "y",   bk.y);
        Attr(node, "ori", wxString::FromUTF8(bk.ori));
        root->AddChild(node);
    }

    // ── Sensors ─────────────────────────────────────────────────────────────
    for (const auto& fb : plan.sensors) {
        wxXmlNode* node = MakeNode("fb");
        Attr(node, "id",      wxString::FromUTF8(fb.id));
        Attr(node, "x",       fb.x);
        Attr(node, "y",       fb.y);
        Attr(node, "addr",    fb.addr);
        Attr(node, "ori",     wxString::FromUTF8(fb.ori));
        Attr(node, "blockId", wxString::FromUTF8(fb.blockId));
        Attr(node, "role",    wxString::FromUTF8(fb.role));
        root->AddChild(node);
    }

    // ── Switches ────────────────────────────────────────────────────────────
    for (const auto& sw : plan.switches) {
        wxXmlNode* node = MakeNode("sw");
        Attr(node, "id",       wxString::FromUTF8(sw.id));
        Attr(node, "x",        sw.x);
        Attr(node, "y",        sw.y);
        Attr(node, "type",     wxString::FromUTF8(sw.type));
        Attr(node, "ori",      wxString::FromUTF8(sw.ori));
        Attr(node, "addr",     sw.addr);
        Attr(node, "port",     sw.port);
        Attr(node, "protocol", wxString::FromUTF8(sw.protocol));
        root->AddChild(node);
    }

    // ── Signals ─────────────────────────────────────────────────────────────
    for (const auto& sg : plan.signals) {
        wxXmlNode* node = MakeNode("sg");
        Attr(node, "id",      wxString::FromUTF8(sg.id));
        Attr(node, "x",       sg.x);
        Attr(node, "y",       sg.y);
        Attr(node, "ori",     wxString::FromUTF8(sg.ori));
        Attr(node, "blockid", wxString::FromUTF8(sg.blockId));
        root->AddChild(node);
    }

    // ── Routes ──────────────────────────────────────────────────────────────
    for (const auto& rt : plan.routes) {
        wxXmlNode* node = MakeNode("rt");
        Attr(node, "id",        wxString::FromUTF8(rt.id));
        Attr(node, "fromblock", wxString::FromUTF8(rt.fromBlock));
        Attr(node, "toblock",   wxString::FromUTF8(rt.toBlock));
        for (const auto& cmd : rt.switchCmds) {
            wxXmlNode* swNode = MakeNode("sw");
            Attr(swNode, "id",  wxString::FromUTF8(cmd.switchId));
            Attr(swNode, "cmd", wxString::FromUTF8(cmd.cmd));
            node->AddChild(swNode);
        }
        root->AddChild(node);
    }

    if (!doc.Save(wxString::FromUTF8(filePath))) {
        m_lastError = "Failed to save: " + filePath;
        return false;
    }
    return true;
}

} // namespace MC
