// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2025 OpenCloud FontIcon Collector Tool

#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QListWidget>
#include <QTextEdit>
#include <QLabel>
#include <QSplitter>
#include <QScrollArea>
#include <QGridLayout>
#include <QFrame>
#include <QDir>
#include <QDirIterator>
#include <QTextStream>
#include <QRegularExpression>
#include <QDebug>
#include <QFont>
#include <QCommandLineParser>
#include <QGroupBox>
#include <QFontDatabase>

#include "fonticon.h"

using namespace Qt::Literals::StringLiterals;
using namespace OCC::Resources;

struct FontIconUsage {
    QString filePath;
    int lineNumber;
    QString sourceContext;
    QChar glyph;
    FontIcon::FontFamily family;
    FontIcon::Size size;
    QString fullConstructorCall;
};

class FontIconCollectorWidget : public QWidget
{
    Q_OBJECT

public:
    explicit FontIconCollectorWidget(QWidget *parent = nullptr)
        : QWidget(parent)
    {
        setupUI();
        scanForFontIconUsages();
    }

private Q_SLOTS:
    void onUsageSelected(int row)
    {
        if (row < 0 || row >= m_usages.size()) {
            return;
        }

        const auto &usage = m_usages[row];
        
        // Update the glyph display
        FontIcon icon(usage.family, usage.glyph, usage.size);
        QPixmap pixmap = icon.pixmap(QSize(64, 64));
        m_glyphLabel->setPixmap(pixmap);
        
        // Update the details
        m_detailsText->clear();
        m_detailsText->append(u"File: %1"_s.arg(usage.filePath));
        m_detailsText->append(u"Line: %1"_s.arg(usage.lineNumber));
        m_detailsText->append(u"Glyph: %1 (0x%2)"_s.arg(usage.glyph).arg(static_cast<uint16_t>(usage.glyph.unicode()), 4, 16, QChar('0'_L1)));
        m_detailsText->append(u"Family: %1"_s.arg(usage.family == FontIcon::FontFamily::FontAwesome ? u"FontAwesome"_s : u"RemixIcon"_s));
        m_detailsText->append(u"Size: %1"_s.arg(usage.size == FontIcon::Size::Normal ? u"Normal"_s : u"Half"_s));
        m_detailsText->append(u"\n"_s);
        m_detailsText->append(u"Context:"_s);
        m_detailsText->append(usage.sourceContext);
    }

private:
    void setupUI()
    {
        setWindowTitle(u"FontIcon Usage Collector"_s);
        resize(1200, 800);

        auto *layout = new QHBoxLayout(this);
        auto *splitter = new QSplitter(Qt::Horizontal, this);
        
        // Left side: List of usages
        auto *leftWidget = new QWidget;
        auto *leftLayout = new QVBoxLayout(leftWidget);

        leftLayout->addWidget(new QLabel(u"FontIcon Usages Found:"_s));
        m_usagesList = new QListWidget;
        leftLayout->addWidget(m_usagesList);
        
        connect(m_usagesList, &QListWidget::currentRowChanged, this, &FontIconCollectorWidget::onUsageSelected);
        
        // Right side: Details and glyph display
        auto *rightWidget = new QWidget;
        auto *rightLayout = new QVBoxLayout(rightWidget);
        
        // Glyph display
        auto *glyphGroup = new QGroupBox(u"Glyph Preview"_s);
        auto *glyphLayout = new QVBoxLayout(glyphGroup);
        
        m_glyphLabel = new QLabel;
        m_glyphLabel->setAlignment(Qt::AlignCenter);
        m_glyphLabel->setStyleSheet(u"border: 1px solid gray; padding: 10px;"_s);
        m_glyphLabel->setMinimumSize(100, 100);
        glyphLayout->addWidget(m_glyphLabel);
        
        // Details text
        auto *detailsGroup = new QGroupBox(u"Details"_s);
        auto *detailsLayout = new QVBoxLayout(detailsGroup);
        
        m_detailsText = new QTextEdit;
        m_detailsText->setReadOnly(true);
        m_detailsText->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
        detailsLayout->addWidget(m_detailsText);
        
        rightLayout->addWidget(glyphGroup);
        rightLayout->addWidget(detailsGroup);
        
        splitter->addWidget(leftWidget);
        splitter->addWidget(rightWidget);
        splitter->setSizes({400, 800});
        
        layout->addWidget(splitter);
    }

    void scanForFontIconUsages()
    {
        QDir srcDir = QDir(QStringLiteral(SRC_DIR));


        if (!srcDir.exists()) {
            qWarning() << "Could not find src directory";
            return;
        }
        
        qDebug() << "Scanning directory:" << srcDir.absolutePath();
        
        // Recursively scan for C++ files
        QDirIterator it(srcDir.absolutePath(), QStringList() << u"*.cpp"_s << u"*.h"_s, QDir::Files, QDirIterator::Subdirectories);

        while (it.hasNext()) {
            QString filePath = it.next();
            scanFile(filePath);
        }
        
        qDebug() << "Found" << m_usages.size() << "FontIcon usages";
        
        // Populate the list widget
        for (const auto &usage : m_usages) {
            QString displayText = u"%1:%2 - %3"_s.arg(QFileInfo(usage.filePath).fileName(), QString::number(usage.lineNumber), usage.glyph);
            m_usagesList->addItem(displayText);
        }
        
        if (!m_usages.isEmpty()) {
            m_usagesList->setCurrentRow(0);
        }
    }

    void scanFile(const QString &filePath)
    {
        QFile file(filePath);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            return;
        }
        
        QTextStream in(&file);
        QString content = in.readAll();
        QStringList lines = content.split('\n'_L1);

        // Regular expressions to match FontIcon constructor calls
        QRegularExpression fontIconRegex(uR"(FontIcon\s*\(\s*([^)]+)\s*\))"_s);
        QRegularExpression glyphRegex(uR"(u'(.)')"_s);
        QRegularExpression familyRegex(uR"(FontIcon::FontFamily::(\w+))"_s);
        QRegularExpression sizeRegex(uR"(FontIcon::Size::(\w+))"_s);

        for (int lineNum = 0; lineNum < lines.size(); ++lineNum) {
            const QString &line = lines[lineNum];
            
            auto fontIconMatch = fontIconRegex.match(line);
            if (fontIconMatch.hasMatch()) {
                FontIconUsage usage;
                usage.filePath = filePath;
                usage.lineNumber = lineNum + 1;
                usage.fullConstructorCall = fontIconMatch.captured(0);
                
                // Extract glyph
                auto glyphMatch = glyphRegex.match(line);
                if (glyphMatch.hasMatch()) {
                    QString glyphStr = glyphMatch.captured(1);
                    if (!glyphStr.isEmpty()) {
                        usage.glyph = glyphStr[0];
                    }
                } else {
                    // Look for hex unicode like u'\uf015'
                    QRegularExpression hexGlyphRegex(uR"(u'\\u([0-9a-fA-F]{4})')"_s);
                    auto hexMatch = hexGlyphRegex.match(line);
                    if (hexMatch.hasMatch()) {
                        bool ok;
                        uint unicode = hexMatch.captured(1).toUInt(&ok, 16);
                        if (ok) {
                            usage.glyph = QChar(unicode);
                        }
                    } else {
                        // Try to find the glyph directly in the line
                        QRegularExpression directGlyphRegex(uR"(u'(.)')"_s);
                        auto directMatch = directGlyphRegex.match(line);
                        if (directMatch.hasMatch()) {
                            usage.glyph = directMatch.captured(1)[0];
                        } else {
                            usage.glyph = QChar('?'_L1); // Unknown glyph
                        }
                    }
                }
                
                // Extract family (default to FontAwesome)
                auto familyMatch = familyRegex.match(line);
                if (familyMatch.hasMatch()) {
                    QString familyStr = familyMatch.captured(1);
                    usage.family = (familyStr == u"RemixIcon"_s) ? FontIcon::FontFamily::RemixIcon : FontIcon::FontFamily::FontAwesome;
                } else {
                    usage.family = FontIcon::FontFamily::FontAwesome;
                }
                
                // Extract size (default to Normal)
                auto sizeMatch = sizeRegex.match(line);
                if (sizeMatch.hasMatch()) {
                    QString sizeStr = sizeMatch.captured(1);
                    usage.size = (sizeStr == u"Half"_s) ? FontIcon::Size::Half : FontIcon::Size::Normal;
                } else {
                    usage.size = FontIcon::Size::Normal;
                }
                
                // Get context (current line and a few lines around it)
                QStringList contextLines;
                for (int ctx = qMax(0, lineNum - 2); ctx <= qMin(lines.size() - 1, lineNum + 2); ++ctx) {
                    QString prefix = (ctx == lineNum) ? u">>> "_s : u"    "_s;
                    contextLines << u"%1%2: %3"_s.arg(prefix, QString::number(ctx + 1), lines[ctx]);
                }
                usage.sourceContext = contextLines.join('\n'_L1);

                m_usages.append(usage);
            }
        }
    }

private:
    QListWidget *m_usagesList = nullptr;
    QLabel *m_glyphLabel = nullptr;
    QTextEdit *m_detailsText = nullptr;
    QList<FontIconUsage> m_usages;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    app.setApplicationName(u"FontIcon Collector"_s);
    app.setApplicationVersion(u"1.0"_s);

    const QString cascadiaCodeFontPath = u"Cascadia Code NF"_s;
    if (QFontDatabase::hasFamily(cascadiaCodeFontPath)) {
        QApplication::setFont(cascadiaCodeFontPath);
    }
    QCommandLineParser parser;
    parser.setApplicationDescription(u"Collects and displays FontIcon usages from the QSfera Desktop codebase"_s);
    parser.addHelpOption();
    parser.addVersionOption();
    
    parser.process(app);
    
    FontIconCollectorWidget window;
    window.show();
    
    return app.exec();
}

#include "fonticon_collector.moc"
