#include "graphicsItem/graphicsTextItem.h"
#include "graphicsItem/itemControlHandle.h"
#include "graphicsItem/graphicsItemGroup.h"

#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QFont>
#include <QGraphicsScene>
#include <QFocusEvent>
#include <QTextDocument>

GraphicsTextItem::GraphicsTextItem(QGraphicsItem *parent)
    : AbstractShapeType<QGraphicsTextItem>(parent)
{
    m_type = T_item;
    m_pen = QPen(Qt::NoPen);
    m_brush = QBrush(Qt::NoBrush);

    // 8 resize handles
    m_vecHanle.reserve(H_left);
    for (int i = H_leftTop; i <= H_left; i++) {
        auto *h = new ItemControlHandle(this);
        h->setType(T_resize);
        h->setTag(i);
        m_vecHanle.push_back(h);
    }
    // 4 rotate handles
    for (int i = H_rotate_leftTop; i <= H_rotate_leftBottom; i++) {
        auto *h = new ItemControlHandle(this);
        h->setType(T_rotate);
        h->setTag(i);
        m_vecHanle.push_back(h);
    }

    setFlag(QGraphicsItem::ItemIsMovable, false); // we handle move via selector
    setFlag(QGraphicsItem::ItemIsSelectable, true);
    setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
    setAcceptHoverEvents(true);

    QFont defaultFont;
    defaultFont.setPointSize(14);
    setFont(defaultFont);
    setDefaultTextColor(Qt::black);
    setPlainText("Text");

    updateSizeFromText();
    m_boundingRect = QRectF(0, 0, m_dWidth, m_dHeight);
    setTransformOriginPoint(m_boundingRect.center());
    m_lastBoundingRect = m_boundingRect;

    // Keep bounding rect in sync with text content during editing
    connect(document(), &QTextDocument::contentsChanged, this, [this]() {
        prepareGeometryChange();
        updateSizeFromText();
        m_boundingRect = QRectF(0, 0, m_dWidth, m_dHeight);
        setTransformOriginPoint(m_boundingRect.center());
        updateHandles();
        m_lastBoundingRect = m_boundingRect;
    });
}

GraphicsTextItem::~GraphicsTextItem() {}

QString GraphicsTextItem::getPropertyGroup(const QString &propertyName) const
{
    QList<QString> properties = {
        QStringLiteral("text"),
        QStringLiteral("ptPosition"),
        QStringLiteral("textFont"),
        QStringLiteral("textColor"),
        QStringLiteral("backgroundColor")
    };
    
    if (!properties.contains(propertyName))
        return {};
    else
        return QStringLiteral("基本信息");
}

QPainterPath GraphicsTextItem::shape()
{
    QPainterPath path;
    path.addRect(m_boundingRect);
    return path;
}

void GraphicsTextItem::updateSizeFromText()
{
    QSizeF textSize = document()->size();
    double w = qMax(textSize.width(), 40.0);
    double h = qMax(textSize.height(), 20.0);
    m_dWidth = w;
    m_dHeight = h;
}

void GraphicsTextItem::updateCoordinate()
{
    if (!parentItem()) {
        updateSizeFromText();
        prepareGeometryChange();
        m_boundingRect = QRectF(0, 0, m_dWidth, m_dHeight);
        setTransformOriginPoint(m_boundingRect.center());
        updateHandles();
    }
    m_lastBoundingRect = m_boundingRect;
    m_dLastPointSize = font().pointSize();
}

void GraphicsTextItem::updateHandles()
{
    AbstractShapeType<QGraphicsTextItem>::updateHandles();
}

void GraphicsTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    // Background fill
    if (m_brush.style() != Qt::NoBrush) {
        painter->setPen(Qt::NoPen);
        painter->setBrush(m_brush);
        painter->drawRect(m_boundingRect);
    }

    // Text rendering via QGraphicsTextItem
    QGraphicsTextItem::paint(painter, option, widget);

    // Selection indicator
    if (option->state & QStyle::State_Selected) {
        int nPenWidth = 1;
        painter->setPen(QPen(QColor(70, 70, 70), nPenWidth, Qt::DashLine));
        painter->setBrush(Qt::NoBrush);
        painter->drawRect(m_boundingRect_selected);

        painter->setBrush(Qt::red);
        painter->drawEllipse(transformOriginPoint(), 4, 4);
    }
}

void GraphicsTextItem::resize(int nHandle, double dSX, double dSY, const QPointF &basePoint)
{
    switch (nHandle) {
    case H_left:
    case H_right:
        dSY = 1;
        break;
    case H_top:
    case H_bottom:
        dSX = 1;
        break;
    default:
        break;
    }

    QTransform trans;
    trans.translate(basePoint.x(), basePoint.y());
    trans.scale(dSX, dSY);
    trans.translate(-basePoint.x(), -basePoint.y());

    prepareGeometryChange();
    m_boundingRect = trans.mapRect(m_lastBoundingRect);
    m_dWidth = m_boundingRect.width();
    m_dHeight = m_boundingRect.height();

    // Scale font size proportionally from pre-drag value
    double avgScale = (qAbs(dSX) + qAbs(dSY)) / 2.0;
    QFont f = font();
    int newSize = qMax(1, qRound(m_dLastPointSize * avgScale));
    f.setPointSize(newSize);
    setFont(f);

    setTransformOriginPoint(m_boundingRect.center());
    updateHandles();
}

void GraphicsTextItem::move(const QPointF &pt)
{
    moveBy(pt.x(), pt.y());
}

QVariant GraphicsTextItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == QGraphicsItem::ItemSelectedHasChanged) {
        QGraphicsItemGroup *group = dynamic_cast<QGraphicsItemGroup *>(parentItem());
        if (!group)
            setHandleVisible(value.toBool());
        else {
            setSelected(false);
            return QVariant::fromValue<bool>(false);
        }
    }
    return QGraphicsTextItem::itemChange(change, value);
}

void GraphicsTextItem::startEditing()
{
    m_bEditing = true;
    setHandleVisible(false);
    setTextInteractionFlags(Qt::TextEditorInteraction);
    setFocus();
}

void GraphicsTextItem::endEditing()
{
    m_bEditing = false;
    setTextInteractionFlags(Qt::NoTextInteraction);
    updateCoordinate();
    if (isSelected())
        setHandleVisible(true);
}

void GraphicsTextItem::focusOutEvent(QFocusEvent *event)
{
    QGraphicsTextItem::focusOutEvent(event);
    endEditing();
}

void GraphicsTextItem::focusInEvent(QFocusEvent *event)
{
    QGraphicsTextItem::focusInEvent(event);
    setHandleVisible(false);
}

void GraphicsTextItem::createOperationCopy()
{
    m_pOperationCopy = new QGraphicsPathItem(shape());
    m_pOperationCopy->setPen(Qt::DashLine);
    m_pOperationCopy->setPos(pos());
    m_pOperationCopy->setTransformOriginPoint(transformOriginPoint());
    m_pOperationCopy->setTransform(transform());
    m_pOperationCopy->setRotation(rotation());
    m_pOperationCopy->setScale(scale());
    m_pOperationCopy->setZValue(zValue());

    QGraphicsScene *s = scene();
    if (s && m_pOperationCopy) {
        s->addItem(m_pOperationCopy);
        m_movingIniPos = pos();
    }
}

void GraphicsTextItem::removeOperationCopy()
{
    QGraphicsScene *s = scene();
    if (s && m_pOperationCopy) {
        if (pos() != m_pOperationCopy->pos())
            setPos(m_pOperationCopy->pos());
        if (rotation() != m_pOperationCopy->rotation())
            setRotation(m_pOperationCopy->rotation());
        s->removeItem(m_pOperationCopy);
        delete m_pOperationCopy;
        m_pOperationCopy = nullptr;
    }
}

void GraphicsTextItem::moveOperationCopy(const QPointF &distance)
{
    if (m_pOperationCopy)
        m_pOperationCopy->setPos(m_movingIniPos + distance);
}

void GraphicsTextItem::rotateOperationCopy(const double &dAngle)
{
    if (m_pOperationCopy)
        m_pOperationCopy->setRotation(dAngle);
}

void GraphicsTextItem::syncRotationDataFromParent(const double &data)
{
    m_dSyncRotationByParent += data;
    if (m_dSyncRotationByParent > 180)
        m_dSyncRotationByParent -= 360;
    if (m_dSyncRotationByParent < -180)
        m_dSyncRotationByParent += 360;
}

#include "util/serializationUtils.h"

QJsonObject GraphicsTextItem::serialize() const
{
    QJsonObject obj = serializeCommon(this, "text");
    obj["text"] = toPlainText();
    QJsonObject fontObj;
    fontObj["family"] = font().family();
    fontObj["bold"] = font().bold();
    fontObj["italic"] = font().italic();
    fontObj["underline"] = font().underline();
    fontObj["pointSize"] = font().pointSize();
    obj["font"] = fontObj;
    obj["textColor"] = defaultTextColor().name(QColor::HexArgb);
    obj["backgroundColor"] = m_brush.color().name(QColor::HexArgb);
    return obj;
}

#include "util/serializationRegistry.h"

QGraphicsItem *GraphicsTextItem::createFromJson(const QJsonObject &obj)
{
    auto *item = new GraphicsTextItem();
    item->setPlainText(obj["text"].toString());
    QJsonObject f = obj["font"].toObject();
    QFont font(f["family"].toString(), f["pointSize"].toInt(14));
    font.setBold(f["bold"].toBool());
    font.setItalic(f["italic"].toBool());
    font.setUnderline(f["underline"].toBool());
    item->setFont(font);
    item->setDefaultTextColor(QColor(obj["textColor"].toString()));
    QColor bgColor(obj["backgroundColor"].toString());
    if (bgColor.isValid())
        item->setBrushColor(bgColor);
    applyCommon(item, obj);
    item->updateSizeFromText();
    item->updateCoordinate();
    item->setHandleVisible(false);
    return item;
}

static struct TextItemRegistrar {
    TextItemRegistrar() {
        registerItemFactory("text", &GraphicsTextItem::createFromJson);
    }
} _textItemRegistrar;
