#ifndef DOCUMENT_H
#define DOCUMENT_H

#include <QString>
#include <QDateTime>
#include <QMap>
#include <QVariant>
#include <QObject>
#include <QByteArray>

/**
 * @brief BayTemplate 文档类
 *
 * Document 类作为持久化层，位于 Model 层之下，负责：
 * 1. 序列化/反序列化：将 DesignerScene 中的图元层次结构保存到 JSON/XML，从文件重建场景
 * 2. 状态管理：文件名、保存状态（是否修改过）、版本信息、元数据
 * 3. 与现有架构的集成：通过组合方式持有 DesignerScene 的引用，提供信号与 CMainWindow 通信
 *
 * 设计原则：
 * - 组合优于继承：Document 持有 DesignerScene 的弱引用，不继承 Scene
 * - 单向依赖：Document 只依赖 DesignerScene 的接口，不依赖 CMainWindow
 * - 信号槽通信：通过信号与外部通信修改状态，避免紧耦合
 */
class DesignerScene;
class GraphicsBaseItem;
class GraphicsItemGroup;
class QGraphicsScene;
class QGraphicsItem;
class QJsonObject;

class Document : public QObject
{
    Q_OBJECT

public:
    explicit Document(QObject *parent = nullptr);
    ~Document();

    // =================================================================
    // 场景关联（组合关系）
    // =================================================================

    /**
     * @brief 关联到 DesignerScene
     * @param scene 场景对象，Document 持有其弱引用
     *
     * 通过组合方式关联场景，而不是继承。这符合开闭原则，
     * Document 可以独立于 Scene 存在，需要序列化时才使用 scene 引用。
     */
    void setScene(DesignerScene* scene);

    /**
     * @brief 获取关联的场景
     */
    DesignerScene* scene() const;

    // =================================================================
    // 文件操作
    // =================================================================

    /**
     * @brief 保存文档到文件（覆盖当前文件）
     * @param filename 文件路径，为空则使用当前 filename()
     * @return 成功返回 true
     *
     * 保存流程：
     * 1. 如果 filename 为空且 m_filename 不为空，使用 m_filename
     * 2. 序列化场景内容到 JSON 格式
     * 3. 写入文件
     * 4. 更新 lastSavedTime，调用 setModified(false)
     * 5. 发出 saveStatusChanged 信号
     *
     * 注意：此方法不会更新 m_filename，仅用于覆盖已有文件
     */
    bool saveToFile(const QString& filename = QString());

    /**
     * @brief 另存为（Save As）
     * @param filename 目标文件路径
     * @return 成功返回 true
     *
     * 另存为流程：
     * 1. 序列化场景内容到 JSON 格式
     * 2. 写入文件
     * 3. 更新 m_filename 为目标文件路径
     * 4. 更新 lastSavedTime，调用 setModified(false)
     * 5. 发出 filenameChanged 和 modifiedChanged 信号
     *
     * 与 saveToFile() 的区别：
     * - saveAsToFile() 总是会更新 m_filename
     * - saveAsToFile() 适用于"另存为"操作，改变文档的默认保存路径
     */
    bool saveAsToFile(const QString& filename);

    /**
     * @brief 从文件加载文档
     * @param filename 文件路径
     * @return 成功返回 true
     *
     * 反序列化流程：
     * 1. 读取 JSON 文件
     * 2. 清空当前 scene 的内容
     * 3. 递归重建图元层次结构
     * 4. 更新 m_filename 和 m_modified
     */
    bool loadFromFile(const QString& filename);

    // =================================================================
    // 序列化接口（二进制格式）
    // =================================================================

    /**
     * @brief 序列化为 QByteArray
     * @return JSON 格式的字节数组
     */
    QByteArray serialize() const;

    /**
     * @brief 从 QByteArray 反序列化
     * @param data JSON 格式的字节数组
     * @return 成功返回 true
     */
    bool deserialize(const QByteArray& data);

    // =================================================================
    // 状态管理
    // =================================================================

    /**
     * @brief 文档文件名（可能为空，表示未保存的新文档）
     */
    QString filename() const { return m_filename; }
    void setFilename(const QString& filename) { m_filename = filename; }

    /**
     * @brief 文档是否被修改过（需要保存）
     */
    bool isModified() const { return m_modified; }
    void setModified(bool modified) {
        if (m_modified != modified) {
            m_modified = modified;
            emit modifiedChanged(m_modified);
        }
    }

    /**
     * @brief 文档版本（文件格式版本，用于向前/向后兼容）
     */
    QString version() const { return m_version; }

    /**
     * @brief 创建时间
     */
    QDateTime created() const { return m_created; }

    /**
     * @brief 最后修改时间
     */
    QDateTime modifiedTime() const { return m_modifiedTime; }

    /**
     * @brief 最后保存时间
     */
    QDateTime lastSavedTime() const { return m_lastSavedTime; }

    // =================================================================
    // 元数据（可扩展）
    // =================================================================

    /**
     * @brief 设置自定义元数据
     * @param key 键名
     * @param value 值
     */
    void setMetaData(const QString& key, const QVariant& value);

    /**
     * @brief 获取自定义元数据
     */
    QVariant metaData(const QString& key) const;

signals:
    /**
     * @brief 修改状态改变时发出
     * @param modified 新的修改状态
     *
     * CMainWindow 可连接此信号来更新窗口标题（添加 * 标记）
     */
    void modifiedChanged(bool modified);

    /**
     * @brief 文件名改变时发出（新建、另存为等操作）
     * @param filename 新的文件名
     *
     * CMainWindow 可连接此信号来更新窗口标题
     */
    void filenameChanged(const QString& filename);

    /**
     * @brief 保存/加载操作完成时发出
     * @param success 操作是否成功
     * @param message 成功或失败的消息
     */
    void saveStatusChanged(bool success, const QString& message);

private:
    // 内部实现
    bool saveInternal(const QString& filename);
    bool loadInternal(const QString& filename);

    // 图元序列化/反序列化
    QJsonObject serializeItem(GraphicsBaseItem* item) const;
    void deserializeItem(const QJsonObject& obj, QGraphicsScene* scene, QGraphicsItem* parent);

    QString getTypeString(GraphicsBaseItem* item) const;
    QJsonObject serializeItemProperties(GraphicsBaseItem* item) const;

    // QVariant <-> QJsonValue 转换
    QJsonValue toJsonValue(const QVariant& value) const;
    QVariant fromJsonValue(const QJsonValue& value) const;

    GraphicsBaseItem* deserializeRectItem(const QJsonObject& obj);
    GraphicsBaseItem* deserializeBusSectionItem(const QJsonObject& obj);
    GraphicsBaseItem* deserializePolygonItem(const QJsonObject& obj);
    GraphicsItemGroup* deserializeItemGroup(const QJsonObject& obj, QGraphicsScene* scene, QGraphicsItem* parent);

    QString m_filename;           // 文档文件名
    bool    m_modified;           // 是否被修改
    QString m_version;            // 文件格式版本
    QDateTime m_created;          // 创建时间
    QDateTime m_modifiedTime;     // 最后修改时间
    QDateTime m_lastSavedTime;    // 最后保存时间

    QMap<QString, QVariant> m_metaData;  // 自定义元数据

    DesignerScene* m_pScene;     // 关联的场景（组合关系，非拥有所有权）
};

#endif // DOCUMENT_H
