#include "FunctionScanner.h"

#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QTextStream>
#include <QRegularExpression>

FunctionScanner::FunctionScanner(QObject *parent)
    : QObject(parent)
{
}

// ---------------------------------------------------------------------------
// Verzeichnis rekursiv scannen
// ---------------------------------------------------------------------------
QList<FunctionScanner::FunctionInfo> FunctionScanner::scanDirectory(
    const QString    &rootPath,
    const QStringList &extensions) const
{
    QList<FunctionInfo> results;

    QDirIterator it(rootPath,
                    extensions,
                    QDir::Files,
                    QDirIterator::Subdirectories);

    while (it.hasNext())
    {
        const QString path = it.next();
        results.append(scanFile(path));
    }

    return results;
}

// ---------------------------------------------------------------------------
// Einzelne Datei scannen
// ---------------------------------------------------------------------------
QList<FunctionScanner::FunctionInfo> FunctionScanner::scanFile(const QString &filePath) const
{
    QList<FunctionInfo> results;

    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        return results;
    }

    QTextStream stream(&file);
    stream.setEncoding(QStringConverter::Utf8);

    QStringList lines;
    while (!stream.atEnd())
    {
        lines.append(stream.readLine());
    }

    // Regex für Funktionsdefinitionen:
    // optional: public/protected/private/static/abstract/final
    // gefolgt von: function name(
    static const QRegularExpression funcRegex(
        R"((?:(?:public|protected|private|static|abstract|final)\s+)*)"
        R"(function\s+(&?\s*[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\s*\()",
        QRegularExpression::CaseInsensitiveOption
    );

    for (int i = 0; i < lines.size(); ++i)
    {
        const QString &line = lines[i];

        // Zeilen in Kommentaren überspringen
        const QString trimmed = line.trimmed();
        if (trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("#"))
        {
            continue;
        }

        QRegularExpressionMatch match = funcRegex.match(line);
        if (!match.hasMatch())
        {
            continue;
        }

        FunctionInfo info;
        info.name       = match.captured(1).trimmed();
        info.filePath   = filePath;
        info.line       = i + 1;
        info.className  = detectClassContext(lines, i);
        info.parameters = extractParameters(line, static_cast<int>(match.capturedEnd()) - 1);
        info.signature  = info.name + "(" + info.parameters + ")";

        // Konstruktoren und magische Methoden kennzeichnen
        // aber trotzdem aufnehmen — sie sind nützlich in der Liste

        results.append(info);
    }

    return results;
}

// ---------------------------------------------------------------------------
// Parameter aus der Funktionssignatur extrahieren
// Behandelt auch mehrzeilige Signaturen mit öffnender Klammer am Ende
// ---------------------------------------------------------------------------
QString FunctionScanner::extractParameters(const QString &line, int parenPos)
{
    // Inhalt zwischen ( und ) extrahieren
    // Einfache Version: nur die erste Zeile — reicht für 99% aller Fälle
    const int openParen = parenPos;
    int depth = 0;
    int closePos = -1;

    for (int i = openParen; i < line.length(); ++i)
    {
        if      (line[i] == '(') { ++depth; }
        else if (line[i] == ')')
        {
            --depth;
            if (depth == 0)
            {
                closePos = i;
                break;
            }
        }
    }

    if (closePos == -1)
    {
        // Klammer geht über Zeilenende — gekürzt anzeigen
        return line.mid(openParen + 1).trimmed() + "…";
    }

    return line.mid(openParen + 1, closePos - openParen - 1).trimmed();
}

// ---------------------------------------------------------------------------
// Klassenkontext erkennen — rückwärts durch den Code suchen
// ---------------------------------------------------------------------------
QString FunctionScanner::detectClassContext(const QStringList &lines, int functionLineIndex)
{
    static const QRegularExpression classRegex(
        R"((?:class|interface|trait|enum)\s+([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*))",
        QRegularExpression::CaseInsensitiveOption
    );

    // Rückwärts suchen — letztes class/interface/trait vor dieser Zeile
    for (int i = functionLineIndex - 1; i >= 0; --i)
    {
        QRegularExpressionMatch match = classRegex.match(lines[i]);
        if (match.hasMatch())
        {
            return match.captured(1);
        }
    }

    return QString(); // Globale Funktion
}
