#include "GeneralInterface.h"

#include <QTime>
#include <QRect>
#include <QPoint>
#include <QGraphicsScene>
#include <QGraphicsProxyWidget>
#include <QParallelAnimationGroup>
#include <QPropertyAnimation>

template<typename T>
T GeneralInterface::toInt(const QByteArray &data, int offset, bool networkOrder)
{
    if ((offset + sizeof(T)) > static_cast<size_t>(data.size())) {
        return 0;
    }

    T value;
    memcpy(&value, data.constData() + offset, sizeof(T));

    if (networkOrder) {
        if constexpr (sizeof(T) == 2) {
            return qFromBigEndian(value);
        } else if constexpr (sizeof(T) == 4) {
            return qFromBigEndian(value);
        } else if constexpr (sizeof(T) == 8) {
            return qFromBigEndian<qint64>(value);
        }
    }

    return value;
}

uint8_t GeneralInterface::toUInt8(const QByteArray &data, int offset)
{
    return toInt<uint8_t>(data, offset);
}

uint16_t GeneralInterface::toUInt16(const QByteArray &data, int offset, bool networkOrder)
{
    return toInt<uint16_t>(data, offset, networkOrder);
}

uint32_t GeneralInterface::toUInt32(const QByteArray &data, int offset, bool networkOrder) {
    return toInt<uint32_t>(data, offset, networkOrder);
}

uint64_t GeneralInterface::toUInt64(const QByteArray &data, int offset, bool networkOrder)
{
    return toInt<uint64_t>(data, offset, networkOrder);
}

QByteArray GeneralInterface::networkStructToByteArray(const MSG_HEAD &data)
{
    MSG_HEAD networkData;
    networkData.proto_id = qToBigEndian(data.proto_id);
    networkData.trans_id = qToBigEndian(data.trans_id);
    networkData.length = qToBigEndian(data.length);
    networkData.unit_id = qToBigEndian(data.unit_id);
    networkData.cmd = qToBigEndian(data.cmd);

    return QByteArray(reinterpret_cast<const char*>(&networkData), sizeof(MSG_HEAD));
}

template<typename T>
QByteArray GeneralInterface::encodeValue(T &data, const uint8_t &length)
{
    QByteArray result;
    auto tempData = qToBigEndian(data);
    result.append(0x80 + sizeof(data));
    result.append(length);
    result.append(QByteArray(reinterpret_cast<const char*>(&tempData), sizeof(T)));
    return result;
}

template<typename T>
T GeneralInterface::decodeValue(const QByteArray &data)
{
    return toInt<T>(data);
}

QByteArray GeneralInterface::encodeChargeCtlInfo(const CHARGE_CTL_INFO &data)
{
    QByteArray ctl_array;
    ctl_array.append(encodeValue<const uint32_t>(data.GUNID, 1));
    ctl_array.append(QByteArray(reinterpret_cast<const char*>(&data.EMID), sizeof(uint8_t)));
    ctl_array.append(encodeValue<const uint32_t>(data.requestKWs, 1));
    ctl_array.append(encodeValue<const uint32_t>(data.seconds, 1));
    ctl_array.append(encodeValue<const uint32_t>(data.authorizationResult, 1));
    return QByteArray();
}

charge_gun_basic_info_t GeneralInterface::decodeChargeBasicInfo(const QByteArray &data)
{
    charge_gun_basic_info_t basicInfo;
    int start_index = 2;

    basicInfo.GUNID = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    basicInfo.GUN_Error = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    basicInfo.GUN_State = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    basicInfo.GUN_type = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));

    return basicInfo;
}

charge_gun_charge_info_t GeneralInterface::decodeChargeInfo(const QByteArray &data)
{
    charge_gun_charge_info_t charge_info;
    int start_index = 2;

    charge_info.GUNID = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.SOC = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.startUTC = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.now_UTC = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.startKW = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.now_KW = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.BOX_temp = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.BOARD_temp = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.GUNLine_temp = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.voltage = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));
    start_index += (sizeof(uint32_t) + 2);

    charge_info.current = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));

    return charge_info;
}

ccu_reply_info_t GeneralInterface::decodeReplyInfo(const QByteArray &data)
{
    ccu_reply_info_t reply_info;
    int start_index = 2;
    reply_info.result = decodeValue<uint32_t>(data.mid(start_index, sizeof(uint32_t)));

    return reply_info;
}

QString GeneralInterface::formatMillisecondDifference(qint64 ms1, qint64 ms2)
{
    qint64 diffMs = qAbs(ms1 - ms2); // 取绝对值

    QTime time(0, 0);
    time = time.addMSecs(diffMs);

    return time.toString("HH:mm:ss");
}

void GeneralInterface::makeLabelJump(QLabel* label) {
    // 创建动画组
    QParallelAnimationGroup *group = new QParallelAnimationGroup(label);

    // 位置动画
    QPropertyAnimation *posAnim = new QPropertyAnimation(label, "pos", group);
    posAnim->setDuration(800);
    posAnim->setEasingCurve(QEasingCurve::OutQuad);
    posAnim->setKeyValueAt(0, label->pos());
    posAnim->setKeyValueAt(0.5, label->pos() + QPoint(0, -80));
    posAnim->setKeyValueAt(1, label->pos());

    // 缩放动画
    QPropertyAnimation *scaleAnim = new QPropertyAnimation(label, "geometry", group);
    scaleAnim->setDuration(800);
    scaleAnim->setEasingCurve(QEasingCurve::OutQuad);
    QRect startRect = label->geometry();
    scaleAnim->setKeyValueAt(0, startRect);
    scaleAnim->setKeyValueAt(0.5, QRect(
                                      startRect.x() - 10,
                                      startRect.y() - 80,
                                      startRect.width() + 20,
                                      startRect.height() + 20
                                      ));
    scaleAnim->setKeyValueAt(1, startRect);

    // 启动动画
    group->start(QAbstractAnimation::DeleteWhenStopped);
}

QString GeneralInterface::getGunIconUrl(const uint8_t &type, bool isError)
{
    QString icon_url = "";
    switch (type) {
    case GUNTYPE_NACS:
        icon_url = QString(":/icons/%1.png").arg("nacs" + QString("%1").arg(isError ? "_failed" : ""));
        break;
    case GUNTYPE_CCS1:
        icon_url = QString(":/icons/%1.png").arg("ccs1" + QString("%1").arg(isError ? "_failed" : ""));
        break;
    case GUNTYPE_CCS2:
        icon_url = QString(":/icons/%1.png").arg("ccs2" + QString("%1").arg(isError ? "_failed" : ""));
        break;
    case GUNTYPE_CHADEMO:
        icon_url = QString(":/icons/%1.png").arg("chademo" + QString("%1").arg(isError ? "_failed" : ""));
        break;
    case GUNTYPE_GBDC:
        icon_url = QString(":/icons/%1.png").arg("gbdc" + QString("%1").arg(isError ? "_failed" : ""));
        break;
    default:
        break;
    }

    return icon_url;
}

bool GeneralInterface::isError(const QList<uint8_t> &error_list)
{
    return std::any_of(error_list.begin(), error_list.end(),
                       [](uint8_t value) { return value > CHARGE_GUN_ERROR_MAX_INDEX; });
}

uint8_t GeneralInterface::getMaxElement(const QList<uint8_t> &state_list)
{
    if (state_list.isEmpty()) {
        return 0; // 或者抛出异常
    }

    auto it = std::max_element(state_list.begin(), state_list.end());
    return *it;
}

void GeneralInterface::setButtonBackground(QPushButton *button, const QString &imageUrl)
{
    QPalette palette;
    palette.setBrush(button->backgroundRole(), QBrush(QPixmap(imageUrl)));
    button->setPalette(palette);
    button->setAutoFillBackground(true);  // 必须设置为true
    button->setFlat(true);  // 移除按钮的默认外观
}

void GeneralInterface::setLineeditBackground(QLineEdit *lineEdit, const QString &imageUrl)
{
    QPalette palette;
    palette.setBrush(lineEdit->backgroundRole(), QBrush(QPixmap(imageUrl)));
    lineEdit->setPalette(palette);
    lineEdit->setAutoFillBackground(true);
}

void GeneralInterface::addRotationAnimation(QLabel *label)
{
    // 创建图形场景和代理
    QGraphicsScene *scene = new QGraphicsScene(label->parentWidget());
    QGraphicsProxyWidget *proxy = scene->addWidget(label);

    // 设置旋转中心为标签中心
    proxy->setTransformOriginPoint(proxy->boundingRect().center());

    // 创建旋转动画
    QPropertyAnimation *animation = new QPropertyAnimation(label, "rotation");
    animation->setDuration(2000);  // 动画持续时间(毫秒)
    animation->setStartValue(0);   // 起始角度
    animation->setEndValue(360);   // 结束角度(360度)
    animation->setLoopCount(-1);   // 无限循环
    animation->start();
}

uint8_t GeneralInterface::getMaxElementWithQMax(const QList<uint8_t> &list)
{
    if (list.isEmpty()) {
        return 0;
    }

    int max = list.first();
    for (int num : list) {
        max = qMax(max, num);
    }
    return max;
}
