#include "document.h"
#include "designerScene.h"
#include "graphicsItem/graphicsBaseItem.h"
#include "graphicsItem/graphicsItemGroup.h"
#include "graphicsItem/graphicsRectItem.h"
#include "graphicsItem/graphicsBusSectionItem.h"
#include "graphicsItem/graphicsPolygonItem.h"

#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QFile>
#include <QDataStream>
#include <QSet>
#include <QJsonArray>
#include <QJsonDocument>
#include <QFile>
#include <QDataStream>

// 文档格式版本号
static const QString DOCUMENT_VERSION = "1.0";

Document::Document(QObject *parent)
    : QObject(parent)
    , m_filename()
    , m_modified(false)
    , m_version(DOCUMENT_VERSION)
    , m_created(QDateTime::currentDateTime())
    , m_modifiedTime(QDateTime::currentDateTime())
    , m_lastSavedTime()
    , m_pScene(nullptr)
{
}

Document::~Document()
{
    // Document 不拥有 scene 的所有权，不需要删除
    m_pScene = nullptr;
}

// =================================================================
// 场景关联
// =================================================================

void Document::setScene(DesignerScene* scene)
{
    m_pScene = scene;

    // 如果关联了新的 scene，连接 selectionChanged 信号来追踪修改
    if (m_pScene) {
        connect(m_pScene, &QGraphicsScene::selectionChanged,
                this, [this]() {
                    // 选择改变本身不代表文档修改，但可以作为用户活动的信号
                    // 实际的修改由具体的操作（添加、删除、移动等）触发
                });
    }
}

DesignerScene* Document::scene() const
{
    return m_pScene;
}

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

bool Document::saveToFile(const QString& filename)
{
    QString targetFile = filename.isEmpty() ? m_filename : filename;

    if (targetFile.isEmpty()) {
        // 没有目标文件名，无法保存
        emit saveStatusChanged(false, tr("未指定文件路径，请使用另存为功能"));
        return false;
    }

    bool success = saveInternal(targetFile);

    if (success) {
        m_lastSavedTime = QDateTime::currentDateTime();
        m_modified = false;

        // 如果传入的文件名与当前文件名不同，更新 m_filename
        if (!filename.isEmpty() && filename != m_filename) {
            m_filename = filename;
            emit filenameChanged(m_filename);
        }

        emit modifiedChanged(false);
        emit saveStatusChanged(true, tr("保存成功"));
    } else {
        emit saveStatusChanged(false, tr("保存失败"));
    }

    return success;
}

bool Document::saveAsToFile(const QString& filename)
{
    if (filename.isEmpty()) {
        emit saveStatusChanged(false, tr("未指定文件路径"));
        return false;
    }

    bool success = saveInternal(filename);

    if (success) {
        QString oldFilename = m_filename;
        m_filename = filename;
        m_lastSavedTime = QDateTime::currentDateTime();
        m_modified = false;

        // 另存为总是会更新文件名
        emit filenameChanged(m_filename);
        emit modifiedChanged(false);
        emit saveStatusChanged(true, tr("另存为成功"));
    } else {
        emit saveStatusChanged(false, tr("另存为失败"));
    }

    return success;
}

bool Document::loadFromFile(const QString& filename)
{
    bool success = loadInternal(filename);

    if (success) {
        m_filename = filename;
        m_modified = false;
        m_lastSavedTime = QDateTime::currentDateTime();
        emit filenameChanged(m_filename);
        emit modifiedChanged(false);
        emit saveStatusChanged(true, tr("加载成功"));
    } else {
        emit saveStatusChanged(false, tr("加载失败"));
    }

    return success;
}

// =================================================================
// 序列化核心实现
// =================================================================

QByteArray Document::serialize() const
{
    if (!m_pScene) {
        return QByteArray();
    }

    QJsonObject root;
    root.insert("version", m_version);
    root.insert("created", m_created.toString(Qt::ISODate));
    root.insert("modified", m_modifiedTime.toString(Qt::ISODate));
    root.insert("filename", m_filename);

    // 序列化元数据
    if (!m_metaData.isEmpty()) {
        QJsonObject metaObj;
        for (auto it = m_metaData.begin(); it != m_metaData.end(); ++it) {
            // QVariant 需要转换为 QJsonValue
            metaObj.insert(it.key(), toJsonValue(it.value()));
        }
        root.insert("metaData", metaObj);
    }

    // 序列化图元
    QJsonArray itemsArray;
    QList<QGraphicsItem*> items = m_pScene->items();

    for (QGraphicsItem* item : items) {
        // 跳过 handle 等辅助元素
        // QGraphicsItem 不是 QObject，所以不能用 qobject_cast
        // GraphicsBaseItem 继承 QObject 和 AbstractShape (QGraphicsItem)，可以用 qgraphicsitem_cast
        GraphicsBaseItem* baseItem = qgraphicsitem_cast<GraphicsBaseItem*>(item);
        if (!baseItem) {
            continue;
        }

        // 双重检查：通过 isValidItem() 确保不是辅助元素（如 ItemControlHandle）
        // ItemControlHandle 是 QGraphicsRectItem 子类，不是 GraphicsBaseItem 子类
        // 即使 qgraphicsitem_cast 错误返回非 null，isValidItem() 也能过滤掉（m_type 为 T_undefined）
        if (!baseItem->isValidItem()) {
            continue;
        }

        QJsonObject itemObj = serializeItem(baseItem);
        itemsArray.append(itemObj);
    }

    root.insert("items", itemsArray);

    QJsonDocument doc(root);
    return doc.toJson(QJsonDocument::Indented);
}

bool Document::deserialize(const QByteArray& data)
{
    if (data.isEmpty() || !m_pScene) {
        return false;
    }

    QJsonParseError jsonError;
    QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
    if (jsonError.error != QJsonParseError::NoError) {
        return false;
    }

    QJsonObject root = doc.object();

    // 解析版本信息
    QString version = root["version"].toString();
    if (version.isEmpty()) {
        return false;
    }

    // 解析时间信息
    if (root.contains("created")) {
        m_created = QDateTime::fromString(root["created"].toString(), Qt::ISODate);
    }
    if (root.contains("modified")) {
        m_modifiedTime = QDateTime::fromString(root["modified"].toString(), Qt::ISODate);
    }

    // 解析元数据
    if (root.contains("metaData")) {
        QJsonObject metaObj = root["metaData"].toObject();
        for (auto it = metaObj.begin(); it != metaObj.end(); ++it) {
            // QJsonValue 需要转换为 QVariant
            m_metaData.insert(it.key(), fromJsonValue(it.value()));
        }
    }

    // 清空当前场景
    if (m_pScene) {
        m_pScene->clear();
    }

    // 反序列化图元
    QJsonArray itemsArray = root["items"].toArray();
    for (auto itemIt : itemsArray) {
        QJsonObject itemObj = itemIt.toObject();
        deserializeItem(itemObj, m_pScene, nullptr);
    }

    return true;
}

// =================================================================
// 内部实现
// =================================================================

bool Document::saveInternal(const QString& filename)
{
    QByteArray data = serialize();
    if (data.isEmpty()) {
        return false;
    }

    QFile file(filename);
    if (!file.open(QIODevice::WriteOnly)) {
        return false;
    }

    file.write(data);
    file.close();
    return true;
}

bool Document::loadInternal(const QString& filename)
{
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly)) {
        return false;
    }

    QByteArray data = file.readAll();
    file.close();

    return deserialize(data);
}

// =================================================================
// 图元序列化/反序列化
// =================================================================

QJsonObject Document::serializeItem(GraphicsBaseItem* item) const
{
    QJsonObject obj;

    // 基本属性
    obj.insert("type", getTypeString(item));
    obj.insert("id", QString::number(reinterpret_cast<quintptr>(item)));

    // 位置和变换
    QPointF pos = item->pos();
    QJsonObject posObj;
    posObj.insert("x", pos.x());
    posObj.insert("y", pos.y());
    obj.insert("pos", posObj);

    obj.insert("rotation", item->rotation());

    QJsonObject scaleObj;
    // Qt 的 scale() 返回 qreal，不是 QPointF
    scaleObj.insert("x", item->scale());
    scaleObj.insert("y", item->scale());
    obj.insert("scale", scaleObj);

    // 样式属性（只用于非组项，GraphicsItemGroup 没有 pen/brush）
    GraphicsItemGroup* group = qgraphicsitem_cast<GraphicsItemGroup*>(item);
    if (!group) {
        // 普通图元才有 pen/brush
        QJsonObject penObj;
        QColor penColor = item->penColor();
        if (penColor.isValid()) {
            penObj.insert("color", penColor.name());
        } else {
            penObj.insert("color", QString());
        }
        penObj.insert("width", item->pen().widthF());
        penObj.insert("style", static_cast<int>(item->pen().style()));
        obj.insert("pen", penObj);

        QJsonObject brushObj;
        brushObj.insert("color", item->brushColor().name());
        obj.insert("brush", brushObj);
    } else {
        // 组没有 pen/brush，插入空对象
        obj.insert("pen", QJsonObject());
        obj.insert("brush", QJsonObject());
    }

    // 尺寸
    obj.insert("width", item->width());
    obj.insert("height", item->height());

    // 类型特定属性
    obj.insert("properties", serializeItemProperties(item));

    // 如果是组，递归序列化子项
    if (group) {
        QJsonArray childrenArray;
        QList<QGraphicsItem*> children = group->childItems();
        for (QGraphicsItem* child : children) {
            // 使用 qgraphicsitem_cast 安全转换，只序列化 GraphicsBaseItem 子类的项
            GraphicsBaseItem* childBase = qgraphicsitem_cast<GraphicsBaseItem*>(child);
            if (childBase) {
                childrenArray.append(serializeItem(childBase));
            }
            // 跳过 ItemControlHandle 等非 GraphicsBaseItem 的子项
        }
        obj.insert("children", childrenArray);
    }

    return obj;
}

void Document::deserializeItem(const QJsonObject& obj, QGraphicsScene* scene, QGraphicsItem* parent)
{
    QString typeStr = obj["type"].toString();

    GraphicsBaseItem* item = nullptr;
    GraphicsItemGroup* group = nullptr;

    // 根据类型创建图元（属性在工厂函数中已设置）
    if (typeStr == "GraphicsRectItem") {
        item = deserializeRectItem(obj);
    } else if (typeStr == "GraphicsBusSectionItem") {
        item = deserializeBusSectionItem(obj);
    } else if (typeStr == "GraphicPolygonItem") {
        item = deserializePolygonItem(obj);
    } else if (typeStr == "GraphicsItemGroup") {
        group = deserializeItemGroup(obj, scene, parent);
        // 先添加到 scene 或父组，再递归处理子项
        if (parent) {
            GraphicsItemGroup* parentGroup = qgraphicsitem_cast<GraphicsItemGroup*>(parent);
            if (parentGroup) {
                parentGroup->addToGroup(group);
            }
        } else {
            scene->addItem(group);
        }
        // 递归处理子项（此时 group 已在 scene 中）
        QJsonArray childrenArray = obj["children"].toArray();
        for (auto childIt : childrenArray) {
            deserializeItem(childIt.toObject(), scene, group);
        }
        // 添加完子项后，更新 group 的 m_boundingRect
        // 使用 Qt 的 QGraphicsItemGroup::boundingRect() 计算实际包围盒，
        // 然后更新 m_boundingRect、m_boundingRect_selected 和 handle 位置
        // 这适用于顶层和嵌套 group（updateCoordinate 对嵌套 group 不更新 m_boundingRect）
        group->updateBoundingRectFromChildren();
        return;
    }

    if (!item) {
        return;
    }

    // 添加到场景或父项
    if (parent) {
        GraphicsItemGroup* parentGroup = qgraphicsitem_cast<GraphicsItemGroup*>(parent);
        if (parentGroup) {
            parentGroup->addToGroup(item);
        }
    } else {
        scene->addItem(item);
    }
    // 普通图元没有子项

    // 添加后更新 handles 位置和 m_boundingRect_selected
    // 这一步至关重要：deserialization 后需要重新计算选中框和 handle 位置
    item->updateHandles();
    item->setHandleVisible(false); // 默认不显示 handle
}

// =================================================================
// QVariant <-> QJsonValue 转换辅助函数
// =================================================================

QJsonValue Document::toJsonValue(const QVariant& value) const
{
    if (value.typeId() == qMetaTypeId<bool>()) {
        return value.toBool();
    } else if (value.typeId() == qMetaTypeId<int>()) {
        return value.toInt();
    } else if (value.typeId() == qMetaTypeId<double>()) {
        return value.toDouble();
    } else if (value.typeId() == QMetaType::Type::QString) {
        return value.toString();
    } else {
        return value.toString();
    }
}

QVariant Document::fromJsonValue(const QJsonValue& value) const
{
    if (value.isDouble()) {
        return value.toDouble();
    } else if (value.isBool()) {
        return value.toBool();
    } else if (value.isArray()) {
        QList<QVariant> list;
        for (const QJsonValue& v : value.toArray()) {
            list.append(fromJsonValue(v));
        }
        return list;
    } else if (value.isObject()) {
        QMap<QString, QVariant> map;
        for (auto it = value.toObject().begin(); it != value.toObject().end(); ++it) {
            map.insert(it.key(), fromJsonValue(it.value()));
        }
        return map;
    } else {
        return value.toString();
    }
}

// =================================================================
// 辅助函数
// =================================================================

QString Document::getTypeString(GraphicsBaseItem* item) const
{
    // 使用动态类型信息获取类型字符串（qobject_cast 要求类型有 Q_OBJECT 宏）
    // GraphicsRectItem, GraphicsBusSectionItem, GraphicsItemGroup 都有 Q_OBJECT 宏
    if (qobject_cast<GraphicsRectItem*>(item)) {
        return "GraphicsRectItem";
    } else if (qobject_cast<GraphicsBusSectionItem*>(item)) {
        return "GraphicsBusSectionItem";
    } else if (qobject_cast<GraphicsItemGroup*>(item)) {
        return "GraphicsItemGroup";
    } else if (qobject_cast<GraphicPolygonItem*>(item)) {
        return "GraphicPolygonItem";
    }
    return "GraphicsBaseItem";
}

QJsonObject Document::serializeItemProperties(GraphicsBaseItem* item) const
{
    QJsonObject props;

    // 类型特定的属性序列化
    GraphicsRectItem* rectItem = qobject_cast<GraphicsRectItem*>(item);
    if (rectItem) {
        props.insert("isRound", rectItem->isRound());
        if (rectItem->isRound()) {
            props.insert("ratioX", rectItem->ratioX());
            props.insert("ratioY", rectItem->ratioY());
        }
    }

    // 多边形顶点序列化
    GraphicPolygonItem* polygonItem = qobject_cast<GraphicPolygonItem*>(item);
    if (polygonItem) {
        QPolygonF points = polygonItem->getPoints();
        QJsonArray pointsArray;
        for (const QPointF& pt : points) {
            QJsonObject ptObj;
            ptObj.insert("x", pt.x());
            ptObj.insert("y", pt.y());
            pointsArray.append(ptObj);
        }
        props.insert("points", pointsArray);
    }

    return props;
}

GraphicsBaseItem* Document::deserializeRectItem(const QJsonObject& obj)
{
    // 根据保存的属性重建矩形
    double width = obj["width"].toDouble();
    double height = obj["height"].toDouble();

    // 先读取 properties，获取 isRound 以在构造时创建正确的 control handles
    QJsonObject props = obj["properties"].toObject();
    bool isRound = props["isRound"].toBool(false);

    // 图元的原点在中心，因此 rect 的左上角为 (-width/2, -height/2)
    // 在构造函数中已经设置了 boundingRect，所以不需要再调用 setWidth/setHeight
    QRect rect(-width/2, -height/2, width, height);
    GraphicsRectItem* item = new GraphicsRectItem(rect, isRound);

    // 从 JSON 恢复属性
    QJsonObject posObj = obj["pos"].toObject();
    item->setPos(posObj["x"].toDouble(), posObj["y"].toDouble());
    item->setRotation(obj["rotation"].toDouble());

    // 使用 setScale 而不是 setTransform（避免与 item 的 transform 冲突）
    QJsonObject scaleObj = obj["scale"].toObject();
    double scaleX = scaleObj["x"].toDouble();
    double scaleY = scaleObj["y"].toDouble();
    if (scaleX != 1.0 || scaleY != 1.0) {
        item->setScale(qMax(scaleX, scaleY)); // 使用统一缩放
    }

    QJsonObject penObj = obj["pen"].toObject();
    if (penObj.isEmpty()) {
        // 如果 pen 对象为空（来自组的序列化），使用默认值
        QPen pen(Qt::black);
        pen.setWidthF(1.0);
        pen.setStyle(Qt::SolidLine);
        item->setPen(pen);
    } else {
        QPen pen;
        pen.setColor(QColor(penObj["color"].toString()));
        pen.setWidthF(penObj["width"].toDouble());
        pen.setStyle(static_cast<Qt::PenStyle>(penObj["style"].toInt()));
        item->setPen(pen);
    }

    QJsonObject brushObj = obj["brush"].toObject();
    if (brushObj.isEmpty()) {
        item->setBrush(QBrush(Qt::NoBrush));
    } else {
        QBrush brush;
        brush.setColor(QColor(brushObj["color"].toString()));
        item->setBrush(brush);
    }

    // 恢复圆角比例
    if (isRound) {
        item->setRatioX(props["ratioX"].toDouble(0.1));
        item->setRatioY(props["ratioY"].toDouble(0.1));
    }

    return item;
}

GraphicsBaseItem* Document::deserializeBusSectionItem(const QJsonObject& obj)
{
    // 总线段重建
    double width = obj["width"].toDouble();
    double height = obj["height"].toDouble();
    QRect rect(-width/2, -height/2, width, height);
    GraphicsBusSectionItem* item = new GraphicsBusSectionItem(rect);

    // 从 JSON 恢复属性
    QJsonObject posObj = obj["pos"].toObject();
    item->setPos(posObj["x"].toDouble(), posObj["y"].toDouble());
    item->setRotation(obj["rotation"].toDouble());

    QJsonObject scaleObj = obj["scale"].toObject();
    double scaleX = scaleObj["x"].toDouble();
    double scaleY = scaleObj["y"].toDouble();
    if (scaleX != 1.0 || scaleY != 1.0) {
        item->setScale(qMax(scaleX, scaleY));
    }

    QJsonObject penObj = obj["pen"].toObject();
    if (penObj.isEmpty()) {
        QPen pen(Qt::black);
        pen.setWidthF(1.0);
        pen.setStyle(Qt::SolidLine);
        item->setPen(pen);
    } else {
        QPen pen;
        pen.setColor(QColor(penObj["color"].toString()));
        pen.setWidthF(penObj["width"].toDouble());
        pen.setStyle(static_cast<Qt::PenStyle>(penObj["style"].toInt()));
        item->setPen(pen);
    }

    QJsonObject brushObj = obj["brush"].toObject();
    if (brushObj.isEmpty()) {
        item->setBrush(QBrush(Qt::NoBrush));
    } else {
        QBrush brush;
        brush.setColor(QColor(brushObj["color"].toString()));
        item->setBrush(brush);
    }

    return item;
}

GraphicsBaseItem* Document::deserializePolygonItem(const QJsonObject& obj)
{
    GraphicPolygonItem* item = new GraphicPolygonItem();

    // 恢复顶点数据（必须在设置变换之前，因为 addPoint 内部使用 mapFromScene 转换，
    // 此时 item 无变换，mapToScene/mapFromScene 为恒等变换，顶点坐标不变）
    QJsonObject props = obj["properties"].toObject();
    QJsonArray pointsArray = props["points"].toArray();
    for (const QJsonValue& val : pointsArray) {
        QJsonObject ptObj = val.toObject();
        QPointF localPt(ptObj["x"].toDouble(), ptObj["y"].toDouble());
        item->addPoint(item->mapToScene(localPt));
    }

    // 从 JSON 恢复变换属性
    QJsonObject posObj = obj["pos"].toObject();
    item->setPos(posObj["x"].toDouble(), posObj["y"].toDouble());
    item->setRotation(obj["rotation"].toDouble());

    QJsonObject scaleObj = obj["scale"].toObject();
    double scaleX = scaleObj["x"].toDouble();
    double scaleY = scaleObj["y"].toDouble();
    if (scaleX != 1.0 || scaleY != 1.0) {
        item->setScale(qMax(scaleX, scaleY));
    }

    QJsonObject penObj = obj["pen"].toObject();
    if (penObj.isEmpty()) {
        QPen pen(Qt::black);
        pen.setWidthF(1.0);
        pen.setStyle(Qt::SolidLine);
        item->setPen(pen);
    } else {
        QPen pen;
        pen.setColor(QColor(penObj["color"].toString()));
        pen.setWidthF(penObj["width"].toDouble());
        pen.setStyle(static_cast<Qt::PenStyle>(penObj["style"].toInt()));
        item->setPen(pen);
    }

    QJsonObject brushObj = obj["brush"].toObject();
    if (brushObj.isEmpty()) {
        item->setBrush(QBrush(Qt::NoBrush));
    } else {
        QBrush brush;
        brush.setColor(QColor(brushObj["color"].toString()));
        item->setBrush(brush);
    }

    // 从顶点数据更新 boundingRect，否则 hit-test 和 handles 都会失效
    item->updateBoundingRectFromPoints();

    return item;
}

GraphicsItemGroup* Document::deserializeItemGroup(const QJsonObject& obj,
                                                   QGraphicsScene* scene,
                                                   QGraphicsItem* parent)
{
    GraphicsItemGroup* group = new GraphicsItemGroup(parent);

    // 先设置位置、旋转等变换属性
    QJsonObject posObj = obj["pos"].toObject();
    group->setPos(posObj["x"].toDouble(), posObj["y"].toDouble());
    group->setRotation(obj["rotation"].toDouble());

    QJsonObject scaleObj = obj["scale"].toObject();
    double scaleX = scaleObj["x"].toDouble();
    double scaleY = scaleObj["y"].toDouble();
    if (scaleX != 1.0 || scaleY != 1.0) {
        group->setScale(qMax(scaleX, scaleY));
    }

    // 注意：不设置宽高，因为 GraphicsItemGroup 的 m_boundingRect 需要在添加子项后才能正确计算
    // 在 deserializeItem() 中，添加子项后会调用 updateCoordinate() 和 updateHandles()
    // 如果 group 没有 parent（顶层 group），updateCoordinate() 会自动更新 m_boundingRect
    // 如果 group 有 parent，我们需要在 addChildren 后手动调用 updateHandles() 来更新 handle 位置

    return group;
}

void Document::setMetaData(const QString& key, const QVariant& value)
{
    m_metaData.insert(key, value);
    m_modifiedTime = QDateTime::currentDateTime();
    if (m_pScene) {
        setModified(true);
    }
}

QVariant Document::metaData(const QString& key) const
{
    return m_metaData.value(key);
}
