#include "add-user-panel.h"
#include "../PasswordLineEdit/password-line-edit.h"
#include "../MessageDialog/message-dialog.h"
#include "../DialogManager/dialog-manager.h"
#include "../ModalOverlay/modal-overlay-manager.h"
#include <QLabel>
#include <QFile>
#include <QTextStream>
#include <QKeyEvent>
#include <QDebug>

AddUserPanel::AddUserPanel(QWidget* parent) : OverlayPanelBase(":/plugin/add-user-panel.qss", parent) {
    // Use base-provided containers: contentLayout() and bottomLayout()
    auto* contentLayout = this->contentLayout();
    auto* bottomLayout = this->bottomLayout();

    auto* form = new QFormLayout();
    form->setSpacing(12);
    form->setHorizontalSpacing(16);
    form->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);

    QFont fieldFont; fieldFont.setPixelSize(14); fieldFont.setWeight(QFont::Normal);

    m_uidEdit = new QLineEdit();
    m_uidEdit->setPlaceholderText(tr("Auto"));
    m_uidEdit->setFixedHeight(32); m_uidEdit->setFont(fieldFont);
    form->addRow(tr("User ID"), m_uidEdit);

    m_fullNameEdit = new QLineEdit();
    m_fullNameEdit->setPlaceholderText(tr("Enter"));
    m_fullNameEdit->setFixedHeight(32); m_fullNameEdit->setFont(fieldFont);
    form->addRow(tr("Full Name"), m_fullNameEdit);

    m_loginEdit = new QLineEdit();
    m_loginEdit->setPlaceholderText(tr("Enter"));
    m_loginEdit->setFixedHeight(32); m_loginEdit->setFont(fieldFont);
    form->addRow(tr("Login"), m_loginEdit);

    m_passwordEdit = new PasswordLineEdit();
    m_passwordEdit->setPlaceholderText(tr("Enter"));
    m_passwordEdit->setFixedHeight(32); m_passwordEdit->setFont(fieldFont);
    form->addRow(tr("Password"), m_passwordEdit);

    m_groupCombo = new QComboBox();
    m_groupCombo->setFixedHeight(32); m_groupCombo->setFont(fieldFont);
    m_groupCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    form->addRow(tr("Primary Group"), m_groupCombo);

    contentLayout->addLayout(form);

    // 使用基类创建统一的内联告警行：上下边距0，图标与文本间距6
    this->createInlineErrorRow(form, /*topBottomMargin=*/0, /*iconTextSpacing=*/8);


    auto* buttonLayout = new QHBoxLayout();
    buttonLayout->addStretch();
    m_cancelButton = new DialogButton(tr("Cancel"), DialogButton::Cancel);
    m_confirmButton = new DialogButton(tr("Add"), DialogButton::Confirm);
    m_confirmButton->setEnabled(false);
    buttonLayout->addWidget(m_cancelButton);
    buttonLayout->addWidget(m_confirmButton);
    bottomLayout->addLayout(buttonLayout);


    connect(m_cancelButton, &QToolButton::clicked, this, [this]{ emit requestClose(); });
    connect(m_confirmButton, &QToolButton::clicked, this, &AddUserPanel::onConfirm);
    connect(m_uidEdit, &QLineEdit::textChanged, this, &AddUserPanel::validateInputs);
    connect(m_fullNameEdit, &QLineEdit::textChanged, this, &AddUserPanel::validateInputs);
    connect(m_loginEdit, &QLineEdit::textChanged, this, &AddUserPanel::validateInputs);
    connect(m_passwordEdit, &QLineEdit::textChanged, this, &AddUserPanel::validateInputs);

    connect(m_loginEdit, &QLineEdit::textChanged, this, [this]() {
        const QString login = m_loginEdit->text().trimmed();
        if (!login.isEmpty()) {
            if (m_groupCombo->count() > 0 && m_groupCombo->itemData(0).toString() == "__username__") {
                m_groupCombo->removeItem(0);
            }
            m_groupCombo->insertItem(0, login + tr(" (new, default)"));
            m_groupCombo->setItemData(0, "__username__");
            m_groupCombo->setCurrentIndex(0);
        } else {
            if (m_groupCombo->count() > 0 && m_groupCombo->itemData(0).toString() == "__username__") {
                m_groupCombo->removeItem(0);
            }
            int usersIndex = m_groupCombo->findText("users", Qt::MatchFixedString | Qt::MatchCaseSensitive);
            if (usersIndex < 0) {
                // Case-insensitive fallback (omit MatchCaseSensitive)
                usersIndex = m_groupCombo->findText("users", Qt::MatchFixedString);
            }
            if (usersIndex >= 0) {
                m_groupCombo->setCurrentIndex(usersIndex);
            }
        }
    });

    form->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter);
    for (int r = 0; r < form->rowCount(); ++r) {
        if (auto *item = form->itemAt(r, QFormLayout::LabelRole)) {
            if (auto *lbl = qobject_cast<QLabel*>(item->widget())) {
                lbl->setMinimumHeight(32);
                lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
                QFont lf = lbl->font(); lf.setPixelSize(14); lf.setWeight(QFont::Normal); lbl->setFont(lf);
                lbl->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
            }
        }
    }

    loadGroups();
    loadNextAvailableUid();
    if (m_loginEdit->text().trimmed().isEmpty()) {
        int usersIndex = m_groupCombo->findText("users", Qt::MatchFixedString | Qt::MatchCaseSensitive);
        if (usersIndex < 0) usersIndex = m_groupCombo->findText("users", Qt::MatchFixedString);
        if (usersIndex >= 0) m_groupCombo->setCurrentIndex(usersIndex);
    }
    m_loginEdit->setFocus();
    // Inline error label already added above between form and buttons
}

void AddUserPanel::setInputsEnabled(bool enabled) {
    m_uidEdit->setEnabled(enabled);
    m_fullNameEdit->setEnabled(enabled);
    m_loginEdit->setEnabled(enabled);
    m_passwordEdit->setEnabled(enabled);
    m_groupCombo->setEnabled(enabled);
    m_confirmButton->setEnabled(enabled && m_confirmButton->isEnabled());
}

void AddUserPanel::showError(const QString& msg) {
    setInputsEnabled(true);
    m_state = Idle;
    // Runtime/process errors: popup only; validation stays inline.
    hideInlineError();
    DialogManager::instance().showError(tr("Add User Failed"), msg, this);
    // Re-run validation to restore confirm button when fields are still valid
    validateInputs();
    emit userCreateFailed(msg);
}

bool AddUserPanel::isValidLogin(const QString& login) const {
    static QRegularExpression re("^[a-z_][a-z0-9_-]*[$]?$", QRegularExpression::CaseInsensitiveOption);
    return re.match(login).hasMatch() && login.length() <= 32;
}

void AddUserPanel::loadGroups() {
    m_groupCombo->clear();
    QFile f("/etc/group");
    if (f.open(QFile::ReadOnly | QFile::Text)) {
        QTextStream ts(&f);
        while (!ts.atEnd()) {
            const QString line = ts.readLine();
            const QStringList parts = line.split(":");
            if (parts.size() >= 1) {
                const QString name = parts.at(0).trimmed();
                if (!name.isEmpty()) m_groupCombo->addItem(name);
            }
        }
    }
}

void AddUserPanel::loadNextAvailableUid() {
    int uidMin = 1000;
    int uidMax = 60000;
    QFile loginDefs("/etc/login.defs");
    if (loginDefs.open(QFile::ReadOnly | QFile::Text)) {
        QTextStream ts(&loginDefs);
        while (!ts.atEnd()) {
            const QString line = ts.readLine().trimmed();
            if (line.startsWith("UID_MIN")) {
                const QStringList parts = line.split(QRegularExpression("\\s+"));
                if (parts.size() >= 2) {
                    bool ok = false; int val = parts.at(1).toInt(&ok); if (ok && val > 0) uidMin = val;
                }
            } else if (line.startsWith("UID_MAX")) {
                const QStringList parts = line.split(QRegularExpression("\\s+"));
                if (parts.size() >= 2) {
                    bool ok = false; int val = parts.at(1).toInt(&ok); if (ok && val > 0) uidMax = val;
                }
            }
        }
    }

    int maxUid = uidMin - 1;
    QFile passwd("/etc/passwd");
    if (passwd.open(QFile::ReadOnly | QFile::Text)) {
        QTextStream ts(&passwd);
        while (!ts.atEnd()) {
            const QString line = ts.readLine();
            const QStringList parts = line.split(":");
            if (parts.size() >= 3) {
                bool ok = false; int uid = parts.at(2).toInt(&ok);
                if (ok && uid >= uidMin && uid <= uidMax && uid > maxUid) maxUid = uid;
            }
        }
    }
    const int nextUid = maxUid + 1;
    m_uidEdit->setText(QString::number(nextUid));
    m_uidEdit->setPlaceholderText(tr("Default: %1").arg(nextUid));
}

void AddUserPanel::validateInputs() {
    m_lastValidationError.clear();
    QWidget *errorField = nullptr;
    const QString login = m_loginEdit->text().trimmed();
    const QString pwd = m_passwordEdit->text();
    const QString uidText = m_uidEdit->text().trimmed();

    if (login.isEmpty()) {
        m_lastValidationError = tr("Login name is required");
        errorField = m_loginEdit;
    } else if (!isValidLogin(login)) {
        m_lastValidationError = tr("Invalid login name");
        errorField = m_loginEdit;
    } else if (pwd.isEmpty()) {
        m_lastValidationError = tr("Password is required");
        errorField = m_passwordEdit;
    } else if (pwd.length() < 6) {
        m_lastValidationError = tr("Password must be at least 6 characters");
        errorField = m_passwordEdit;
    } else if (!uidText.isEmpty()) {
        bool okInt = false; int uid = uidText.toInt(&okInt);
        if (!okInt || uid < 1000) {
            m_lastValidationError = tr("UID must be a number >= 1000 or left empty");
            errorField = m_uidEdit;
        }
    }

    bool ok = m_lastValidationError.isEmpty();
    if (!ok && errorField) {
        showInlineError(m_lastValidationError);
    } else {
        hideInlineError();
    }
    m_confirmButton->setEnabled(ok && m_state == Idle);
}

QStringList AddUserPanel::buildUseraddArgs() const {
    QStringList args; args << "-m";
    int idx = m_groupCombo->currentIndex();
    const QString login = m_loginEdit->text().trimmed();
    if (idx >= 0 && m_groupCombo->itemData(idx).toString() == "__username__") {
        args << "-U";
    } else if (idx >= 0) {
        QString grp = m_groupCombo->currentText().trimmed();
        int suffixPos = grp.indexOf(" ("); if (suffixPos > 0) grp = grp.left(suffixPos);
        if (!grp.isEmpty() && grp != login) args << "-g" << grp; else args << "-U";
    } else {
        args << "-U";
    }
    const QString full = m_fullNameEdit->text().trimmed(); if (!full.isEmpty()) args << "-c" << full;
    const QString uid = m_uidEdit->text().trimmed(); if (!uid.isEmpty()) args << "-u" << uid;
    args << login;
    return args;
}

void AddUserPanel::onConfirm() {
    validateInputs();
    if (!m_confirmButton->isEnabled()) return; // Bubble already displayed for validation errors
    setInputsEnabled(false);
    startUseradd();
}

void AddUserPanel::startUseradd() {
    if (m_proc) { m_proc->deleteLater(); m_proc = nullptr; }
    m_proc = new QProcess(this);
    m_state = CreatingUser;
    connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &AddUserPanel::onUseraddFinished);
    connect(m_proc, &QProcess::errorOccurred, this, &AddUserPanel::onProcError);
    QStringList args; args << "/usr/sbin/useradd"; args << buildUseraddArgs();
    m_proc->start("pkexec", args);
}

void AddUserPanel::onUseraddFinished(int exitCode, QProcess::ExitStatus) {
    if (exitCode == 0) { startChpasswd(); return; }
    const QString err = QString::fromUtf8(m_proc->readAllStandardError());
    const QString out = QString::fromUtf8(m_proc->readAllStandardOutput());
    const QString fullMsg = (out + "\n" + err).trimmed();
    if (exitCode == 127) showError(tr("Authentication failed"));
    else if (fullMsg.contains("already exists", Qt::CaseInsensitive)) showError(tr("User already exists"));
    else if (fullMsg.contains("invalid", Qt::CaseInsensitive)) showError(tr("Invalid parameters for useradd"));
    else if (fullMsg.contains("Not authorized", Qt::CaseInsensitive)) showError(tr("Authentication failed"));
    else if (fullMsg.isEmpty()) showError(tr("Failed to create user (exit code %1). Authentication may have been cancelled.").arg(exitCode));
    else showError(tr("Failed to create user: %1").arg(fullMsg));
}

void AddUserPanel::startChpasswd() {
    if (m_proc) { m_proc->deleteLater(); m_proc = nullptr; }
    m_proc = new QProcess(this);
    m_state = SettingPassword;
    connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &AddUserPanel::onChpasswdFinished);
    connect(m_proc, &QProcess::errorOccurred, this, &AddUserPanel::onProcError);
    QStringList args; args << "/usr/sbin/chpasswd";
    m_proc->start("pkexec", args);
    const QString line = m_loginEdit->text().trimmed() + ":" + m_passwordEdit->text();
    m_proc->write(line.toUtf8());
    m_proc->closeWriteChannel();
}

void AddUserPanel::onChpasswdFinished(int exitCode, QProcess::ExitStatus) {
    if (exitCode == 0) {
        emit userCreateSucceeded();
        emit requestClose();
        return;
    }
    const QString err = QString::fromUtf8(m_proc->readAllStandardError());
    const QString out = QString::fromUtf8(m_proc->readAllStandardOutput());
    const QString fullMsg = (out + "\n" + err).trimmed();
    if (exitCode == 127 || fullMsg.contains("Not authorized", Qt::CaseInsensitive)) showError(tr("Authentication failed"));
    else if (fullMsg.isEmpty()) showError(tr("Failed to set password (exit code %1)").arg(exitCode));
    else showError(tr("Failed to set password: %1").arg(fullMsg));
}

void AddUserPanel::onProcError(QProcess::ProcessError) {
    if (m_state == CreatingUser) showError(tr("Failed to run useradd (permission denied or missing command)"));
    else if (m_state == SettingPassword) showError(tr("Failed to run chpasswd (permission denied or missing command)"));
    else showError(tr("Operation failed"));
}
