#include "SignatureHelper.h"
#include "SignatureTooltip.h"
#include "CodeEditor.h"

#include <QTextCursor>
#include <QTextBlock>
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QRect>
#include <QRegularExpression>

SignatureHelper::SignatureHelper(CodeEditor *editor)
    : QObject(editor)
    , m_editor(editor)
{
    // Tooltip als Kind des Viewports — bleibt im Fenster
    m_tooltip = new SignatureTooltip(editor->window());

    loadDatabase();

    connect(m_editor, &CodeEditor::cursorPositionChanged,
            this, &SignatureHelper::onCursorPositionChanged);
}

// ---------------------------------------------------------------------------
// Datenbank laden
// ---------------------------------------------------------------------------
void SignatureHelper::loadDatabase()
{
    QFile f(":/php_functions.json");
    if (!f.open(QIODevice::ReadOnly))
    {
        return;
    }

    const QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
    if (!doc.isArray())
    {
        return;
    }

    for (const QJsonValue &val : doc.array())
    {
        const QJsonObject obj = val.toObject();
        const QString name    = obj["name"].toString();
        if (name.isEmpty())
        {
            continue;
        }

        FunctionInfo info;
        info.signature   = obj["signature"].toString();
        info.description = obj["desc"].toString();
        m_functions.insert(name.toLower(), info);
    }
}

// ---------------------------------------------------------------------------
// Cursor-Bewegung auswerten
// ---------------------------------------------------------------------------
void SignatureHelper::onCursorPositionChanged()
{
    const QTextCursor cursor  = m_editor->textCursor();
    const QString     block   = cursor.block().text();
    const int         col     = cursor.columnNumber();
    const QString     leftText = block.left(col);

    const QString funcName = extractFunctionName(leftText);

    if (funcName.isEmpty())
    {
        m_tooltip->hide();
        return;
    }

    // Klammern zählen — wenn alle geschlossen, Tooltip ausblenden
    if (countOpenParens(leftText) <= 0)
    {
        m_tooltip->hide();
        return;
    }

    const QString key = funcName.toLower();
    if (!m_functions.contains(key))
    {
        m_tooltip->hide();
        return;
    }

    const FunctionInfo &info = m_functions[key];

    // Position unter dem Cursor berechnen
    const QRect cursorRect = m_editor->cursorRect(cursor);
    const QPoint globalPos = m_editor->viewport()->mapToGlobal(
        QPoint(cursorRect.left(), cursorRect.bottom() + 4)
    );

    m_tooltip->showSignature(info.signature, info.description, globalPos);
}

// ---------------------------------------------------------------------------
// Funktionsnamen links vor der öffnenden Klammer extrahieren
// ---------------------------------------------------------------------------
QString SignatureHelper::extractFunctionName(const QString &text) const
{
    // Wir suchen das letzte '(' das zu einem Funktionsnamen gehört.
    // Dabei müssen wir verschachtelte Klammern korrekt behandeln.
    int depth = 0;
    int openPos = -1;

    for (int i = text.length() - 1; i >= 0; --i)
    {
        const QChar ch = text[i];
        if (ch == ')')
        {
            ++depth;
        }
        else if (ch == '(')
        {
            if (depth == 0)
            {
                openPos = i;
                break;
            }
            --depth;
        }
    }

    if (openPos <= 0)
    {
        return QString();
    }

    // Funktionsnamen direkt links von '(' lesen
    int end = openPos - 1;

    // Leerzeichen überspringen
    while (end >= 0 && text[end].isSpace())
    {
        --end;
    }

    if (end < 0)
    {
        return QString();
    }

    // Bezeichner-Zeichen sammeln (Buchstaben, Ziffern, _, :, \)
    int start = end;
    while (start > 0 &&
           (text[start - 1].isLetterOrNumber() ||
            text[start - 1] == '_'             ||
            text[start - 1] == ':'             ||
            text[start - 1] == '\\'))
    {
        --start;
    }

    const QString name = text.mid(start, end - start + 1);

    // Schlüsselwörter und leere Namen ausschließen
    static const QStringList keywords = {
        "if", "else", "elseif", "while", "for", "foreach",
        "switch", "match", "catch", "function", "fn"
    };

    if (name.isEmpty() || keywords.contains(name.toLower()))
    {
        return QString();
    }

    // Nur den letzten Teil nach :: oder -> nehmen
    const int colonPos    = name.lastIndexOf("::");
    const int arrowPos    = name.lastIndexOf("->");
    const int backslashPos = name.lastIndexOf("\\");
    const int splitPos = qMax(backslashPos, qMax(colonPos, arrowPos));

    if (splitPos >= 0)
    {
        return name.mid(splitPos + (name[splitPos] == ':' ? 2 : (name[splitPos] == '\\' ? 1 : 2)));
    }

    return name;
}

// ---------------------------------------------------------------------------
// Offene Klammern zählen
// ---------------------------------------------------------------------------
int SignatureHelper::countOpenParens(const QString &text) const
{
    int depth = 0;
    bool inString     = false;
    QChar stringChar;

    for (int i = 0; i < text.length(); ++i)
    {
        const QChar ch = text[i];

        // Einfache String-Erkennung (kein vollständiger PHP-Parser)
        if (!inString && (ch == '\'' || ch == '"'))
        {
            inString   = true;
            stringChar = ch;
            continue;
        }
        if (inString)
        {
            if (ch == stringChar && (i == 0 || text[i - 1] != '\\'))
            {
                inString = false;
            }
            continue;
        }

        if      (ch == '(') { ++depth; }
        else if (ch == ')') { --depth; }
    }

    return depth;
}
