#include "accounts_controller.h"
#include <QWidget>
#include <QScrollArea>
#include <QFrame>
#include <QVBoxLayout>
#include <QFile>
#include <QDebug>
#include <QLabel>
#include <QLineEdit>
#include <QAbstractButton>
#include <QPushButton>
#include <QToolButton>
#include <QDBusInterface>
#include <QDBusReply>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QProcess>

#include "ui_accounts.h"
#include "../services/user_service.h"
#include "../services/autologin_helper.h"
#include "../services/current_user_helper.h"
#include "../services/privilege_helper.h"
#include "../widgets/UserListPanel/user-list-panel.h"
#include "../widgets/AvatarWidget/avatar-widget.h"
#include "../widgets/ModalOverlay/modal-overlay-manager.h"
#include "../widgets/ChangePasswordDialog/change-password-panel.h"
#include "../widgets/AddUserDialog/add-user-panel.h"
#include "../widgets/DeleteUserConfirmPanel/delete-user-confirm-panel.h"
#include "../widgets/ChangeOtherUserPasswordDialog/change-other-user-password-panel.h"
#include "../widgets/DialogManager/dialog-manager.h"
#include "../widgets/MessageDialog/message-dialog.h"

AccountsController::AccountsController(QWidget* parent)
    : QWidget(parent)
{
    m_content = new QWidget(this);
    m_content->setObjectName("AccountsControllerContent");

    Ui::Accounts ui;
    ui.setupUi(m_content);

    auto* container = m_content->findChild<QWidget*>("userListContainer");
    if (container) {
        m_panel = new UserListPanel(container);
        if (auto* lay = qobject_cast<QVBoxLayout*>(container->layout())) {
            lay->addWidget(m_panel);
        }
    }

    // Fetch current user
    m_currentUser = CurrentUserHelper::currentUsername();

    // Wire services
    m_userService = new UserService(m_panel ? static_cast<QObject*>(m_panel.data()) : static_cast<QObject*>(m_content.data()));
    auto users = m_userService->fetchUsers();

    QString currentFullName;
    if (!m_currentUser.isEmpty()) {
        for (const auto& u : users) {
            if (u.username == m_currentUser) { currentFullName = u.realName; break; }
        }
    }
    if (auto* nameLbl = m_content->findChild<QLabel*>("currentUserNameLabel")) {
        if (!m_currentUser.isEmpty()) nameLbl->setText(m_currentUser);
    }
    if (auto* fullEdit = m_content->findChild<QLineEdit*>("fullNameLineEdit")) {
        if (!currentFullName.isEmpty()) fullEdit->setText(currentFullName);
        else if (!m_currentUser.isEmpty()) fullEdit->setText(m_currentUser);
        fullEdit->setProperty("originalText", fullEdit->text());

        QPointer<QLineEdit> fullEditPtr(fullEdit);
        auto submitFullName = [this, fullEditPtr]() {
            if (!m_content || !fullEditPtr) return;
            if (m_currentUser.isEmpty()) return;
            const QString newName = fullEditPtr->text().trimmed();
            const QString original = fullEditPtr->property("originalText").toString();
            if (newName.isEmpty() || newName == original) return;

            QDBusInterface mgr("org.freedesktop.Accounts",
                               "/org/freedesktop/Accounts",
                               "org.freedesktop.Accounts",
                               QDBusConnection::systemBus());
            if (!mgr.isValid()) {
                qDebug() << "Accounts DBus manager invalid when setting full name" << QDBusConnection::systemBus().lastError();
                return;
            }
            QDBusReply<QDBusObjectPath> rPath = mgr.call("FindUserByName", m_currentUser);
            if (!rPath.isValid()) {
                qDebug() << "FindUserByName failed for" << m_currentUser << rPath.error();
                return;
            }
            const QString objPath = rPath.value().path();
            QDBusInterface userIf("org.freedesktop.Accounts",
                                   objPath,
                                   "org.freedesktop.Accounts.User",
                                   QDBusConnection::systemBus());
            if (!userIf.isValid()) {
                qDebug() << "User interface invalid at" << objPath << QDBusConnection::systemBus().lastError();
                return;
            }
            QDBusMessage reply = userIf.call("SetRealName", newName);
            if (reply.type() == QDBusMessage::ErrorMessage) {
                qDebug() << "SetRealName failed:" << reply.errorName() << reply.errorMessage();
                DialogManager::instance().showError(QObject::tr("Save Full Name Failed"), QObject::tr("Failed to save full name: %1").arg(reply.errorMessage()), m_content->window());
                return;
            }

            fullEditPtr->setProperty("originalText", newName);
            if (auto* avatar = m_content->findChild<AvatarWidget*>("avatarLabel")) {
                avatar->setDisplayName(newName);
            }
        };

        QObject::connect(fullEdit, &QLineEdit::editingFinished, this, submitFullName);
        QObject::connect(fullEdit, &QLineEdit::returnPressed, this, submitFullName);
    }

    if (!m_currentUser.isEmpty()) {
        users.erase(std::remove_if(users.begin(), users.end(), [&](const UserRecord& u){
            return u.username == m_currentUser;
        }), users.end());
    }

    const bool isAdmin = PrivilegeHelper::isAdminUser(m_currentUser);

    if (m_panel) {
        m_panel->setCurrentUserIsAdmin(isAdmin);
        m_panel->setUsers(users);
    }

    m_userService->startMonitoring();
    connect(m_userService, &UserService::userUpdated, this, [this](const UserRecord& u){
        if (!m_content) return;
        if (u.username == m_currentUser) {
            if (auto* fullEdit = m_content->findChild<QLineEdit*>("fullNameLineEdit")) {
                fullEdit->blockSignals(true);
                fullEdit->setText(u.realName.isEmpty() ? u.username : u.realName);
                fullEdit->setProperty("originalText", fullEdit->text());
                fullEdit->blockSignals(false);
            }
            if (auto* avatar = m_content->findChild<AvatarWidget*>("avatarLabel")) {
                avatar->setDisplayName(u.realName.isEmpty() ? u.username : u.realName);
            }
        } else if (m_panel) {
            m_panel->updateUser(u);
        }
    });
    connect(m_userService, &UserService::userAdded, this, [this](const UserRecord& u){
        if (!m_panel) return;
        if (u.username == m_currentUser) return;
        m_panel->addUser(u);
    });
    connect(m_userService, &UserService::userRemoved, this, [this](const QString& username){
        if (!m_panel) return;
        if (username == m_currentUser) return;
        m_panel->removeUser(username);
    });

    // Auto login switch
    if (auto* autoSwitch = m_content->findChild<QAbstractButton*>("autoLoginSwitch")) {
        if (!m_currentUser.isEmpty()) {
            autoSwitch->setChecked(AutoLoginHelper::isAutoLoginEnabled(m_currentUser));
        }
        QObject::connect(autoSwitch, &QAbstractButton::toggled, this,
            [this](bool enabled) {
                if (!m_content) return;
                if (m_currentUser.isEmpty()) return;
                QString errorMsg;
                if (!AutoLoginHelper::setAutoLogin(m_currentUser, enabled, &errorMsg)) {
                    if (!errorMsg.contains("cancel") && !errorMsg.isEmpty()) {
                        DialogManager::instance().showError(QObject::tr("Auto Login Change Failed"), QObject::tr("Failed to change auto login: %1").arg(errorMsg), m_content->window());
                    }
                    if (auto* sw = m_content->findChild<QAbstractButton*>("autoLoginSwitch")) {
                        sw->blockSignals(true);
                        sw->setChecked(!enabled);
                        sw->blockSignals(false);
                    }
                }
            }
        );
    }

    if (auto* changePwdBtn = m_content->findChild<QPushButton*>("changePasswordButton")) {
        QObject::connect(changePwdBtn, &QPushButton::clicked, this, [this]() {
            if (!m_content) return;
            if (m_currentUser.isEmpty()) return;
            QWidget* host = m_content->window();
            auto *mgr = ModalOverlayManager::instance(host);
            auto *panel = new ChangePasswordPanel(m_currentUser);
            ModalOverlayManager::PanelOptions opts;
            opts.title = QObject::tr("Change Password");
            opts.fixedWidth = 464;
            opts.dismissOnOutsideClick = false;
            opts.showHeader = true;
            opts.showCloseButton = true;
            auto handle = mgr->showPanel(panel, opts);
            QObject::connect(panel, &ChangePasswordPanel::requestClose, panel, [mgr, handle]{ mgr->closePanel(handle); });
        });
    }
    // Add user
    if (auto* addUserBtn = m_content->findChild<QPushButton*>("addUserButton")) {
        QObject::connect(addUserBtn, &QPushButton::clicked, this, [this]() {
            if (!m_content) return;
            QWidget* host = m_content->window();
            if (!host) return;
            auto* mgr = ModalOverlayManager::instance(host);
            auto* panel = new AddUserPanel();
            ModalOverlayManager::PanelOptions opts;
            opts.title = QObject::tr("Add User");
            opts.fixedWidth = 464;
            opts.dismissOnOutsideClick = false;
            opts.showHeader = true;
            opts.showCloseButton = true;
            opts.onClosed = [panel]() { /* child auto-deleted */ };
            auto handle = mgr->showPanel(panel, opts);
            QObject::connect(panel, &AddUserPanel::requestClose, panel, [mgr, handle]() { mgr->closePanel(handle); });
            QObject::connect(panel, &AddUserPanel::userCreateSucceeded, this, [this](){
                if (m_userService) m_userService->refresh();
            });
        });
    }

    if (m_panel) {
        QObject::connect(m_panel, &UserListPanel::changePasswordRequested, this, [this](const QString& username){
            if (username.isEmpty()) return;
            if (!m_content) return;
            QWidget* host = m_content->window();
            auto *mgr = ModalOverlayManager::instance(host);
            auto *otherPwdPanel = new ChangeOtherUserPasswordPanel(username);
            ModalOverlayManager::PanelOptions opts;
            opts.title = QObject::tr("Change Password for %1").arg(username);
            opts.fixedWidth = 464;
            opts.dismissOnOutsideClick = false;
            opts.showHeader = true;
            opts.showCloseButton = true;
            auto handle = mgr->showPanel(otherPwdPanel, opts);
            QObject::connect(otherPwdPanel, &ChangeOtherUserPasswordPanel::requestClose, otherPwdPanel, [mgr, handle]{ mgr->closePanel(handle); });
        });
        QObject::connect(m_panel, &UserListPanel::deleteUserRequested, this, [this](const QString& username){
            if (username.isEmpty()) return;
            if (!m_content) return;
            QWidget* host = m_content->window();
            auto* mgr = ModalOverlayManager::instance(host);
            auto* confirmPanel = new DeleteUserConfirmPanel(username);
            ModalOverlayManager::PanelOptions opts;
            opts.title = QString();
            opts.fixedWidth = 464;
            opts.dismissOnOutsideClick = false;
            opts.showHeader = false;
            opts.showCloseButton = false;
            auto handle = mgr->showPanel(confirmPanel, opts);
            QObject::connect(confirmPanel, &DeleteUserConfirmPanel::cancelRequested, confirmPanel, [mgr, handle]{ mgr->closePanel(handle); });
            QObject::connect(confirmPanel, &DeleteUserConfirmPanel::deleteConfirmed, confirmPanel,
                [this, mgr, handle](const QString& user){
                    mgr->closePanel(handle);
                    if (!m_content) return;
                    QProcess* proc = new QProcess(m_content);
                    QObject::connect(proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
                        this, [this, proc, user](int exitCode, QProcess::ExitStatus) {
                            proc->deleteLater();
                            if (exitCode != 0) {
                                QString err = QString::fromUtf8(proc->readAllStandardError());
                                QString out = QString::fromUtf8(proc->readAllStandardOutput());
                                QString msg = (out + "\n" + err).trimmed();
                                if (msg.isEmpty()) msg = QObject::tr("Failed to delete user (exit code %1)").arg(exitCode);
                                if (m_content) {
                                    MessageDialog::showError(QObject::tr("Delete User Failed"), QObject::tr("Failed to delete user '%1': %2").arg(user, msg), m_content->window());
                                }
                                return;
                            }

                            // Keep UI consistent even if AccountsService signal is delayed.
                            if (m_userService) m_userService->refresh();
                        });
                    QStringList args; args << "/usr/sbin/userdel" << "-r" << user;
                    proc->start("pkexec", args);
                });
        });
    }

    QFile qssFile(":/plugin/accounts.qss");
    QString qss;
    if (qssFile.exists() && qssFile.open(QFile::ReadOnly | QFile::Text)) {
        qss = QString::fromUtf8(qssFile.readAll());
        qssFile.close();
    }

    auto *scroll = new QScrollArea(this);
    scroll->setObjectName("AccountsControllerScroll");
    scroll->setWidgetResizable(true);
    scroll->setFrameShape(QFrame::NoFrame);
    scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    scroll->setWidget(m_content);
    if (!qss.isEmpty()) {
        scroll->setStyleSheet(qss);
    }

    const auto pushButtons = m_content->findChildren<QPushButton*>();
    for (auto* b : pushButtons) {
        b->setFocusPolicy(Qt::NoFocus);
        b->setAutoDefault(false);
        b->setDefault(false);
        QObject::connect(b, &QPushButton::clicked, b, [b]{ b->clearFocus(); });
    }
    const auto toolButtons = m_content->findChildren<QToolButton*>();
    for (auto* b : toolButtons) {
        b->setFocusPolicy(Qt::NoFocus);
        QObject::connect(b, &QToolButton::clicked, b, [b]{ b->clearFocus(); });
    }

    auto *layout = new QVBoxLayout(this);
    layout->setContentsMargins(0,0,0,0);
    layout->addWidget(scroll);
}
