#include "gitfilesystemmodel.h"
#include <QProcess>
#include <QDir>
#include <QFileInfo>

GitFileSystemModel::GitFileSystemModel(QObject *parent)
    : QFileSystemModel(parent)
{
    setFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
    connect(this, &QFileSystemModel::directoryLoaded, this, &GitFileSystemModel::onDirectoryLoaded);
    connect(this, &QFileSystemModel::rootPathChanged, this, [this](const QString &path){
        updateGitStatus(path);
    });

    _refreshTimer.setInterval(5000);
    connect(&_refreshTimer, &QTimer::timeout, this, &GitFileSystemModel::refreshGitStatus);
    _refreshTimer.start();
}

void GitFileSystemModel::onDirectoryLoaded(const QString &path) {
    updateGitStatus(path);
}

void GitFileSystemModel::refreshGitStatus() {
    updateGitStatus(rootPath());
}

bool GitFileSystemModel::event(QEvent *event) {
    return QFileSystemModel::event(event);
}

QVariant GitFileSystemModel::getRootIndex() const {
    return QVariant::fromValue(index(rootPath()));
}

QString GitFileSystemModel::findGitRepo(const QString &path) const {
    QDir dir(path);
    while (dir.exists()) {
        if (QFileInfo(dir.filePath(".git")).exists()) {
            return dir.absolutePath();
        }
        if (!dir.cdUp()) {
            break;
        }
    }
    return QString();
}

void GitFileSystemModel::updateGitStatus(const QString &repoPath) {
    QString gitPath = findGitRepo(repoPath);
    if (gitPath.isEmpty()) {
        _gitStatuses.clear();
        return; // emit dataChanged maybe?
    }

    QProcess process;
    process.setWorkingDirectory(gitPath);
    process.start("git", QStringList() << "status" << "--porcelain");
    process.waitForFinished(2000);

    QString output = process.readAllStandardOutput();
    QStringList lines = output.split('\n', Qt::SkipEmptyParts);

    QMap<QString, QString> newStatuses;
    for (const QString &line : lines) {
        if (line.length() > 3) {
            QString status = line.left(2);
            QString file = line.mid(3).trimmed();
            newStatuses[QDir(gitPath).filePath(file)] = status;
        }
    }

    if (_gitStatuses != newStatuses) {
        _gitStatuses = newStatuses;
        // Ideally emit dataChanged for all visible indices.
        emit dataChanged(index(rootPath()), index(rootPath()), {GitStatusRole});
    }
}

QHash<int, QByteArray> GitFileSystemModel::roleNames() const {
    QHash<int, QByteArray> roles = QFileSystemModel::roleNames();
    roles[GitStatusRole] = "gitStatus";
    roles[IsFileRole] = "isFile";
    roles[IsDirectoryRole] = "isDirectory";
    return roles;
}

QVariant GitFileSystemModel::data(const QModelIndex &index, int role) const {
    if (role == GitStatusRole) {
        QString path = filePath(index);
        return _gitStatuses.value(path, "");
    } else if (role == IsFileRole) {
        return QFileInfo(filePath(index)).isFile();
    } else if (role == IsDirectoryRole) {
        return QFileInfo(filePath(index)).isDir();
    }
    return QFileSystemModel::data(index, role);
}

