#include "autologin_helper.h"

#include <QDebug>
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QTextStream>

namespace {

struct SddmAutologinConfig {
    QString user;
    QString session;
    bool reloginSeen = false;
};

QStringList sddmConfigFilesInOrder()
{
    QStringList configFiles;
    if (QFile::exists("/etc/sddm.conf")) {
        configFiles << QStringLiteral("/etc/sddm.conf");
    }

    QDir confDir("/etc/sddm.conf.d");
    if (confDir.exists()) {
        const auto files = confDir.entryList({"*.conf"}, QDir::Files);
        for (const auto& file : files) {
            configFiles << confDir.filePath(file);
        }
    }

    return configFiles;
}

SddmAutologinConfig readEffectiveSddmAutologinConfig()
{
    SddmAutologinConfig cfg;
    const auto configFiles = sddmConfigFilesInOrder();

    for (const auto& path : configFiles) {
        QFile file(path);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
            continue;

        QTextStream in(&file);
        bool inAutologin = false;

        while (!in.atEnd()) {
            QString line = in.readLine().trimmed();
            if (line.isEmpty() || line.startsWith('#') || line.startsWith(';'))
                continue;

            if (line == "[Autologin]") {
                inAutologin = true;
                continue;
            }
            if (line.startsWith('[')) {
                inAutologin = false;
                continue;
            }

            if (!inAutologin)
                continue;

            if (line.startsWith("User=")) {
                cfg.user = line.mid(5).trimmed();
            } else if (line.startsWith("Session=")) {
                cfg.session = line.mid(8).trimmed();
            } else if (line.startsWith("Relogin=")) {
                cfg.reloginSeen = true;
            }
        }
    }

    return cfg;
}

}

QString AutoLoginHelper::detectDisplayManager()
{
    QProcess proc;
    proc.start("systemctl", {"status", "display-manager"});
    proc.waitForFinished(3000);
    QString output = QString::fromUtf8(proc.readAllStandardOutput());
    
    if (output.contains("sddm.service")) return "sddm";
    if (output.contains("lightdm.service")) return "lightdm";
    if (output.contains("gdm")) return "gdm";
    
    return QString();
}

bool AutoLoginHelper::isAutoLoginEnabled(const QString& username)
{
    QString dm = detectDisplayManager();
    
    if (dm == "sddm") {
        const auto cfg = readEffectiveSddmAutologinConfig();
        return !username.isEmpty() && cfg.user == username;
    }
    else if (dm == "lightdm") {
        QFile file("/etc/lightdm/lightdm.conf");
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
            return false;
        
        QTextStream in(&file);
        while (!in.atEnd()) {
            QString line = in.readLine().trimmed();
            if (line.startsWith("autologin-user=")) {
                return line.mid(15).trimmed() == username;
            }
        }
    }
    
    return false;
}

bool AutoLoginHelper::setAutoLogin(const QString& username, bool enable, QString* errorMsg)
{
    QString dm = detectDisplayManager();
    if (dm.isEmpty()) {
        if (errorMsg) *errorMsg = "Could not detect display manager";
        return false;
    }
    
    QString script;
    
    if (dm == "sddm") {
        // Prefer writing a dedicated snippet under /etc/sddm.conf.d.
        // Many systems don't ship /etc/sddm.conf, and editing the global file can fail.
        // Important: /etc/sddm.conf.d is applied in lexicographic order on many distros.
        // A vendor file like "sddm-bianbu.conf" sorts AFTER "99-...", so "99-" is NOT
        // reliably the last override. Use a "zz-" prefix to ensure we apply last.
        const QString conf = QStringLiteral("/etc/sddm.conf.d/zz-bianbu-accounts-autologin.conf");
        const QString legacyConf = QStringLiteral("/etc/sddm.conf.d/99-bianbu-accounts-autologin.conf");
        if (enable) {
            const auto cfg = readEffectiveSddmAutologinConfig();
            // Create the directory and overwrite our snippet.
            // Login names are validated elsewhere (no quotes/newlines), so direct substitution is safe here.
            if (!cfg.session.isEmpty()) {
                script = QString(
                    "install -d -m 0755 /etc/sddm.conf.d && "
                    "rm -f %1 && "
                    "printf '[Autologin]\\nUser=%2\\nSession=%3\\n' > %4"
                ).arg(legacyConf, username, cfg.session, conf);
            } else {
                script = QString(
                    "install -d -m 0755 /etc/sddm.conf.d && "
                    "rm -f %1 && "
                    "printf '[Autologin]\\nUser=%2\\n' > %3"
                ).arg(legacyConf, username, conf);
            }
        } else {
            // Disable by overriding with empty User/Session. Some vendor configs ship
            // autologin in /etc/sddm.conf.d; we must override both fields.
            script = QString(
                "install -d -m 0755 /etc/sddm.conf.d && "
                "rm -f %1 && "
                "printf '[Autologin]\\nUser=\\nSession=\\nRelogin=false\\n' > %2"
            ).arg(legacyConf, conf);
        }
    }
    else if (dm == "lightdm") {
        if (enable) {
            script = QString(
                "sed -i '/^autologin-user=/d' /etc/lightdm/lightdm.conf && "
                "sed -i '/^\\[Seat:\\*\\]/a autologin-user=%1' /etc/lightdm/lightdm.conf"
            ).arg(username);
        } else {
            script = "sed -i '/^autologin-user=/d' /etc/lightdm/lightdm.conf";
        }
    }
    else {
        if (errorMsg) *errorMsg = QString("Unsupported display manager: %1").arg(dm);
        return false;
    }
    
    QProcess proc;
    proc.start("pkexec", {"sh", "-c", script});
    proc.waitForFinished(30000);
    
    if (proc.exitCode() != 0) {
        QString err = QString::fromUtf8(proc.readAllStandardError());
        qDebug() << "pkexec failed:" << proc.exitCode() << err;
        
        if (errorMsg) {
            if (err.contains("dismissed") || err.contains("cancelled") || 
                proc.exitCode() == 126 || proc.exitCode() == 127) {
                *errorMsg = "Authentication cancelled";
            } else {
                *errorMsg = err.isEmpty() ? "Operation failed" : err;
            }
        }
        return false;
    }
    
    qDebug() << "Auto login" << (enable ? "enabled" : "disabled") << "for" << username;
    return true;
}

