#include "tray_ui_logic.h"

#include <Qt>

namespace {
constexpr int kSidePopupGapPx = 2;
}

QString normalizedControllerForCompare(const QString &input, const QString &defaultControlInput)
{
    const QString trimmed = input.trimmed();
    return trimmed.isEmpty() ? defaultControlInput.trimmed() : trimmed;
}

bool backendStateRequiresReloginPrompt(const QString &backendState)
{
    const QString state = backendState.trimmed();
    return !state.isEmpty() && state != QStringLiteral("NoState") && state != QStringLiteral("NeedsLogin");
}

bool controllerInputChanged(const QString &currentInput,
                            const QString &newInput,
                            const QString &defaultControlInput)
{
    return normalizedControllerForCompare(currentInput, defaultControlInput) !=
           normalizedControllerForCompare(newInput, defaultControlInput);
}

bool controllerSwitchNeedsLogoutPrompt(const QString &currentInput,
                                       const QString &newInput,
                                       const QString &defaultControlInput,
                                       const QString &backendState)
{
    return controllerInputChanged(currentInput, newInput, defaultControlInput) &&
           backendStateRequiresReloginPrompt(backendState);
}

bool advertiseExitEnableNeedsConfirmation(bool enabled)
{
    return enabled;
}

bool shouldShowAuthenticatedMenus(const QString &backendState)
{
    const QString state = backendState.trimmed();
    return state == QStringLiteral("Stopped") || state == QStringLiteral("Starting") ||
           state == QStringLiteral("Running");
}

bool shouldShowLoginAction(const QString &backendState)
{
    return !shouldShowAuthenticatedMenus(backendState);
}

bool shouldShowReauthAction(const QString &backendState)
{
    return shouldShowAuthenticatedMenus(backendState);
}

bool shouldShowConnectAction(const QString &backendState)
{
    const QString state = backendState.trimmed();
    return state == QStringLiteral("Stopped") || state == QStringLiteral("Starting") ||
           state == QStringLiteral("Running");
}

bool shouldShowDisconnectAction(const QString &backendState)
{
    const QString state = backendState.trimmed();
    return state == QStringLiteral("Running") || state == QStringLiteral("Starting");
}

bool shouldEnableRunningOnlyLauncher(const QString &backendState)
{
    return backendState.trimmed() == QStringLiteral("Running");
}

bool shouldShowPeersLauncher(bool showAuthenticatedMenus, bool hasPeerSections)
{
    return showAuthenticatedMenus && hasPeerSections;
}

bool errorSuggestsOperatorGrant(const QString &error)
{
    return error.contains(QStringLiteral("access denied"), Qt::CaseInsensitive);
}

QString loginAuthURLFromSnapshot(const QJsonObject &snapshot)
{
    return snapshot.value(QStringLiteral("authURL")).toString().trimmed();
}

QString advertiseExitActionText(bool advertisesExitNode)
{
    return advertisesExitNode ? QStringLiteral("正用作出口节点") : QStringLiteral("用作出口节点…");
}

QString exitMenuTitleText(const QString &currentExitLabel)
{
    const QString current = currentExitLabel.trimmed();
    if (current.isEmpty() || current == QStringLiteral("不使用")) {
        return QStringLiteral("出口节点");
    }
    return QStringLiteral("出口节点(%1)").arg(current);
}

QString exitListTitleText(bool hasExitNodeChoices)
{
    return hasExitNodeChoices ? QStringLiteral("出口节点") : QStringLiteral("无可用出口节点");
}

bool isSyntheticNoExitNodeChoice(const QString &stableID, const QString &name)
{
    return stableID.trimmed().isEmpty() && name.trimmed() == QStringLiteral("不使用");
}

QString submenuLauncherText(const QString &title)
{
    return QStringLiteral("%1 ▸").arg(title);
}

QString peersLauncherText()
{
    return submenuLauncherText(QStringLiteral("网内设备"));
}

QString accountLauncherText(const QString &accountLabel)
{
    const QString account = accountLabel.trimmed();
    if (account.isEmpty()) {
        return submenuLauncherText(QStringLiteral("账号"));
    }
    return submenuLauncherText(QStringLiteral("账号: %1").arg(account));
}

QString selfRootActionText(const QString &selfName, const QString &primaryIP)
{
    const QString name = selfName.trimmed();
    const QString ip = primaryIP.trimmed();
    if (name.isEmpty()) {
        return QStringLiteral("本设备");
    }
    if (ip.isEmpty()) {
        return QStringLiteral("本设备: %1").arg(name);
    }
    return QStringLiteral("本设备: %1 (%2)").arg(name, ip);
}

bool shouldDeferTrayMenuRefresh(bool rootMenuVisible, bool submenuVisible)
{
    return rootMenuVisible || submenuVisible;
}

bool shouldCloseSidePopupAfterRootHide(bool rootMenuVisible,
                                       bool sidePopupVisible,
                                       bool suppressRootHideClose)
{
    return !rootMenuVisible && !sidePopupVisible && !suppressRootHideClose;
}

QPoint rootPopupPosition(const QPoint &anchorGlobalPoint,
                         const QSize &popupSize,
                         const QRect &availableScreenRect)
{
    if (!availableScreenRect.isValid()) {
        return anchorGlobalPoint;
    }

    const int screenLeft = availableScreenRect.left();
    const int screenTop = availableScreenRect.top();
    const int maxX = availableScreenRect.right() - popupSize.width() + 1;
    const int maxY = availableScreenRect.bottom() - popupSize.height() + 1;

    int x = anchorGlobalPoint.x() - popupSize.width() / 2;
    if (x < screenLeft) {
        x = screenLeft;
    }
    if (x > maxX) {
        x = maxX;
    }

    const bool preferAbove = anchorGlobalPoint.y() > availableScreenRect.center().y();
    int y = preferAbove ? (anchorGlobalPoint.y() - popupSize.height()) : anchorGlobalPoint.y();
    if (y < screenTop) {
        y = screenTop;
    }
    if (y > maxY) {
        y = maxY;
    }

    return QPoint(x, y);
}

SidePopupPlacement sidePopupPlacement(const QRect &anchorGlobalRect,
                                      const QSize &popupSize,
                                      const QRect &availableScreenRect,
                                      std::optional<SidePopupEdge> lockedEdge)
{
    if (!anchorGlobalRect.isValid() || !availableScreenRect.isValid()) {
        return {anchorGlobalRect.topRight(), lockedEdge.value_or(SidePopupEdge::Right)};
    }

    const int preferredRightX = anchorGlobalRect.right() + 1 + kSidePopupGapPx;
    const int preferredLeftX = anchorGlobalRect.left() - popupSize.width() - kSidePopupGapPx;
    const int screenLeft = availableScreenRect.left();
    const int screenRightExclusive = availableScreenRect.right() + 1;
    const int maxX = screenRightExclusive - popupSize.width();

    const bool fitsRight = preferredRightX + popupSize.width() <= screenRightExclusive;
    const bool fitsLeft = preferredLeftX >= screenLeft;
    SidePopupEdge edge = SidePopupEdge::Right;
    if (lockedEdge == SidePopupEdge::Right && fitsRight) {
        edge = SidePopupEdge::Right;
    } else if (lockedEdge == SidePopupEdge::Left && fitsLeft) {
        edge = SidePopupEdge::Left;
    } else if (fitsRight) {
        edge = SidePopupEdge::Right;
    } else if (fitsLeft) {
        edge = SidePopupEdge::Left;
    } else {
        const int rightRoom = qMax(0, screenRightExclusive - preferredRightX);
        const int leftRoom = qMax(0, anchorGlobalRect.left() - kSidePopupGapPx - screenLeft);
        edge = (rightRoom >= leftRoom) ? SidePopupEdge::Right : SidePopupEdge::Left;
    }

    int x = (edge == SidePopupEdge::Right) ? preferredRightX : preferredLeftX;
    if (!fitsRight && edge == SidePopupEdge::Right) {
        x = maxX;
    }
    if (!fitsLeft && edge == SidePopupEdge::Left) {
        x = screenLeft;
    }
    if (x < screenLeft) {
        x = screenLeft;
    }
    if (x > maxX) {
        x = maxX;
    }

    int y = anchorGlobalRect.top();
    const int maxY = availableScreenRect.bottom() - popupSize.height() + 1;
    if (y > maxY) {
        y = maxY;
    }
    if (y < availableScreenRect.top()) {
        y = availableScreenRect.top();
    }

    return {QPoint(x, y), edge};
}

QPoint sidePopupPosition(const QRect &anchorGlobalRect,
                         const QSize &popupSize,
                         const QRect &availableScreenRect)
{
    return sidePopupPlacement(anchorGlobalRect, popupSize, availableScreenRect).position;
}
