#include "oauthcallbackserver.h"
#include <QDebug>

OAuthCallbackServer::OAuthCallbackServer(quint16 port, QObject *parent)
    : QObject(parent)
    , m_server(new QTcpServer(this))
    , m_clientSocket(nullptr)
    , m_port(port)
{
    connect(m_server, &QTcpServer::newConnection, this, &OAuthCallbackServer::onNewConnection);
}

OAuthCallbackServer::~OAuthCallbackServer()
{
    stop();
}

bool OAuthCallbackServer::start()
{
    if (m_server->isListening()) {
        qDebug() << "[OAuthCallbackServer] Already listening on port" << m_port;
        return true;
    }

    if (!m_server->listen(QHostAddress::LocalHost, m_port)) {
        QString error = QString("Failed to listen on port %1: %2")
                            .arg(m_port)
                            .arg(m_server->errorString());
        qWarning() << "[OAuthCallbackServer]" << error;
        emit errorOccurred(error);
        return false;
    }

    qDebug() << "[OAuthCallbackServer] Listening on" << redirectUri();
    return true;
}

void OAuthCallbackServer::stop()
{
    if (m_clientSocket) {
        m_clientSocket->disconnectFromHost();
        m_clientSocket->deleteLater();
        m_clientSocket = nullptr;
    }
    if (m_server->isListening()) {
        m_server->close();
        qDebug() << "[OAuthCallbackServer] Stopped";
    }
}

QString OAuthCallbackServer::redirectUri() const
{
    return QString("http://localhost:%1/callback").arg(m_port);
}

void OAuthCallbackServer::onNewConnection()
{
    // Accept only one connection per auth flow; close any previous
    if (m_clientSocket) {
        m_clientSocket->disconnectFromHost();
        m_clientSocket->deleteLater();
    }

    m_clientSocket = m_server->nextPendingConnection();
    connect(m_clientSocket, &QTcpSocket::readyRead, this, &OAuthCallbackServer::onReadyRead);
    connect(m_clientSocket, &QTcpSocket::disconnected, this, &OAuthCallbackServer::onClientDisconnected);

    qDebug() << "[OAuthCallbackServer] New connection from"
             << m_clientSocket->peerAddress().toString();
}

void OAuthCallbackServer::onReadyRead()
{
    if (!m_clientSocket) return;

    QByteArray requestData = m_clientSocket->readAll();
    QString requestStr = QString::fromUtf8(requestData);

    qDebug() << "[OAuthCallbackServer] Received request:" << requestStr.left(200);

    // Parse the first line: "GET /callback?code=...&state=... HTTP/1.1"
    QStringList lines = requestStr.split("\r\n");
    if (lines.isEmpty()) {
        sendErrorResponse(m_clientSocket, "Bad Request", "Empty request");
        return;
    }

    QString requestLine = lines.first();
    QStringList parts = requestLine.split(' ');
    if (parts.size() < 2) {
        sendErrorResponse(m_clientSocket, "Bad Request", "Invalid request line");
        return;
    }

    QString path = parts[1];
    QUrl url(QString("http://localhost%1").arg(path));
    QUrlQuery query(url.query());

    // Check for error parameter (OAuth error response)
    QString errorParam = query.queryItemValue("error");
    if (!errorParam.isEmpty()) {
        QString errorDesc = query.queryItemValue("error_description");
        qWarning() << "[OAuthCallbackServer] OAuth error:" << errorParam << errorDesc;
        sendErrorResponse(m_clientSocket, "Authorization Failed",
                          QString("Error: %1<br>%2").arg(errorParam, errorDesc));
        emit errorOccurred(errorParam + ": " + errorDesc);
        return;
    }

    // Extract the authorization code
    QString code = query.queryItemValue("code");
    if (code.isEmpty()) {
        sendErrorResponse(m_clientSocket, "Bad Request", "No authorization code received");
        emit errorOccurred("No authorization code in callback");
        return;
    }

    QString state = query.queryItemValue("state");

    qDebug() << "[OAuthCallbackServer] Authorization code received (length:" << code.length() << ")";

    // Send success page to browser
    sendSuccessResponse(m_clientSocket);

    // Emit the code and let the authenticator handle the rest
    emit codeReceived(code, state);
}

void OAuthCallbackServer::onClientDisconnected()
{
    if (m_clientSocket) {
        m_clientSocket->deleteLater();
        m_clientSocket = nullptr;
    }
}

void OAuthCallbackServer::sendSuccessResponse(QTcpSocket *socket)
{
    QString body = R"(
<!DOCTYPE html>
<html>
<head><title>Authentication Complete</title>
<style>
  body { font-family: -apple-system, 'Segoe UI', sans-serif; display: flex;
         justify-content: center; align-items: center; height: 100vh;
         margin: 0; background: #f5f5f7; color: #333; }
  .card { background: white; padding: 40px; border-radius: 12px;
          box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; }
  .check { font-size: 48px; color: #34c759; }
  h1 { font-size: 20px; margin: 10px 0; }
  p { color: #666; font-size: 14px; }
</style></head>
<body>
<div class="card">
  <div class="check">&#10003;</div>
  <h1>Authentication Complete</h1>
  <p>You have been successfully authenticated.<br>You can close this window now.</p>
</div>
<script>window.close();</script>
</body>
</html>
)";

    QString response = QString(
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: text/html; charset=utf-8\r\n"
        "Content-Length: %1\r\n"
        "Connection: close\r\n"
        "\r\n"
        "%2"
    ).arg(body.size()).arg(body);

    socket->write(response.toUtf8());
    socket->flush();
    socket->disconnectFromHost();
}

void OAuthCallbackServer::sendErrorResponse(QTcpSocket *socket, const QString &title, const QString &message)
{
    QString body = QString(R"(
<!DOCTYPE html>
<html>
<head><title>%1</title>
<style>
  body { font-family: -apple-system, 'Segoe UI', sans-serif; display: flex;
         justify-content: center; align-items: center; height: 100vh;
         margin: 0; background: #f5f5f7; color: #333; }
  .card { background: white; padding: 40px; border-radius: 12px;
          box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; }
  .err { font-size: 48px; color: #ff3b30; }
  h1 { font-size: 20px; margin: 10px 0; }
  p { color: #888; font-size: 13px; }
</style></head>
<body>
<div class="card">
  <div class="err">&#10007;</div>
  <h1>%1</h1>
  <p>%2</p>
</div>
</body>
</html>
)").arg(title, message);

    QString response = QString(
        "HTTP/1.1 400 Bad Request\r\n"
        "Content-Type: text/html; charset=utf-8\r\n"
        "Content-Length: %1\r\n"
        "Connection: close\r\n"
        "\r\n"
        "%2"
    ).arg(body.size()).arg(body);

    socket->write(response.toUtf8());
    socket->flush();
    socket->disconnectFromHost();
}

#include "oauthcallbackserver.moc"