/*******************************************************************************
 * Copyright (c) 2026, Jan Koester jan.koester@gmx.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 * Neither the name of the <organization> nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#pragma once

#include <memory>
#include <vector>
#include <map>

#include <tinyxml2.h>
#include <json-c/json.h>

/* Undefine Qt's 'slots' macro before including plugin.h which transitively
   includes netplus/connection.h that uses 'slots' as a member name. */
#ifdef slots
#undef slots
#endif
#include "plugin.h"

#include <QObject>
#include <QString>
#include <QList>

class DocumentManager : public QObject {
    Q_OBJECT
public:
    explicit DocumentManager(const QString &pluginDir, QObject *parent = nullptr);
    ~DocumentManager();

    void newDocument();
    bool loadFromFile(const QString &path);
    bool saveToFile(const QString &path);
    QString exportXml();
    bool importXml(const QString &xml);
    bool importHtml(const QString &html);
    QString renderToHtml();

    /* Plugin info */
    QString getPluginTypes() const;

    /* Document tree */
    QString getDocTree() const;

    /* Element operations — return JSON response */
    QString addElement(const QString &parentUuid, const QString &pluginName, int position);
    QString removeElement(const QString &uuid);
    QString moveElementUp(const QString &uuid);
    QString moveElementDown(const QString &uuid);
    QString indentElement(const QString &uuid);
    QString outdentElement(const QString &uuid);
    QString copyElement(const QString &uuid);
    QString pasteElement(const QString &targetUuid);

    /* Property access */
    QString getElementProperties(const QString &uuid);
    QString setElementProperties(const QString &uuid, const QString &propsJson);

private:
    void clearDocument();
    void loadWidgetsFromXml(tinyxml2::XMLElement *xmlEl,
                            blogi::webedit::EditPlugin *parent);
    blogi::webedit::EditPlugin *createPluginByName(const std::string &name);
    blogi::webedit::EditPlugin *findByUuid(blogi::webedit::EditPlugin *root,
                                            const std::string &uuid);

    struct NodeContext {
        blogi::webedit::EditPlugin *node   = nullptr;
        blogi::webedit::EditPlugin *parent = nullptr;
        blogi::webedit::EditPlugin *prev   = nullptr;
    };
    NodeContext findNodeContext(const std::string &uuid);

    json_object *buildTreeJson(const blogi::webedit::EditPlugin *el) const;

    std::unique_ptr<blogi::webedit::EditPluginLoad> _pluginLoader;
    tinyxml2::XMLDocument                           _doc;
    tinyxml2::XMLElement                           *_rootEl = nullptr;

    /* Live widget tree — linked list of top-level elements */
    blogi::webedit::EditPlugin *_docRoot = nullptr;

    /* Owned element storage — raw pointers, freed by plugin loader */
    std::vector<blogi::webedit::EditPlugin*> _ownedElements;

    /* Clipboard */
    tinyxml2::XMLDocument _clipDoc;
    tinyxml2::XMLElement *_clipEl = nullptr;
};
