/*
 * Copyright (C) 2023 Tianjin KYLIN Information Technology Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
**/
#include "lightdmhelper.h"
#include <QDebug>
#include <QLightDM/Greeter>
#include <QFileInfo>
#include "securityuser.h"
#include <pwd.h>
#include "proxymodel.h"
#include "accountservicehelper.h"

LightDMHelper::LightDMHelper(AccountServiceHelper *accountHelper, QObject *parent)
    : QLightDM::Greeter(parent)
    , m_sessionsModel(nullptr)
    , m_secUser(SecurityUser::instance())
    , m_strCurUserName("")
    , m_accountServiceHelper(accountHelper)
{
    //连接到lightdm
    if(!connectToDaemonSync()){
        qDebug() << "connect to Daemon failed";
        exit(1);
    }
    initData();
}

void LightDMHelper::initData()
{
    // 获取会话信息
    m_sessionsModel = new QLightDM::SessionsModel(QLightDM::SessionsModel::LocalSessions, this);
    updateSessionsInfo();
    setSession(defaultSessionHint());
    // 获取用户信息
    m_isShowManualLogin = showManualLoginHint();
    if(!hideUsersHint()){
        m_modelUsers = new UsersModel(this);
        m_modelUsers->setSourceModel(new QLightDM::UsersModel(this));
        connect(m_modelUsers, &UsersModel::userInfoChanged, this, &LightDMHelper::onUsersChanged);
        if(hasValidUsers() == 0) {
            m_isShowManualLogin = true;
        }
    }
    else {
        qDebug() << "hide users, show manual";
        m_isShowManualLogin = true;
    }
    updateUsersInfo();
}

bool LightDMHelper::setSession(const QString &session)
{
    bool bRet = false;
    if (!m_listSessions.contains(session))
        return bRet;
    if (!session.isEmpty() && session != m_strSession) {
        m_strSession = session;
        bRet = true;
    } else if (!session.isEmpty() && session == m_strSession) {
        bRet = true;
    }
    if (bRet)
        Q_EMIT currentSessionChanged(m_strSession);
    return bRet;
}

QString LightDMHelper::session()
{
    return m_strSession;
}

QList<QString> LightDMHelper::getSessionsInfo()
{
    return m_listSessions;
}

void LightDMHelper::startSession()
{
    if(isAuthenticated())
        Q_EMIT authenticationSucess(authenticationUser());


    if(!startSessionSync(m_strSession)) {
        Q_EMIT startSessionFailed();
        Q_EMIT showMessage(tr("failed to start session."), QLightDM::Greeter::MessageTypeError);
    }
}

QString LightDMHelper::getCurrentUser()
{
    return m_strCurUserName;
}

bool LightDMHelper::setCurrentUser(QString strUserName)
{
    bool bRet = false;
    if (!strUserName.isEmpty() && strUserName != m_strCurUserName) {
        if (findUserByName(strUserName)) {
            m_strCurUserName = strUserName;
            bRet = true;
        } else if (struct passwd * pwinfo = getpwnam(strUserName.toLatin1().data())) {
            m_strCurUserName = strUserName;
            bRet = true;
        }
    } else if (!strUserName.isEmpty() && strUserName == m_strCurUserName) {
        bRet = true;
    }
    if (bRet) {
        Q_EMIT currentUserChanged(m_strCurUserName);
    }
    return bRet;
}

UserInfoPtr LightDMHelper::findUserByUid(uid_t id)
{
    for (auto userInfoPtr : m_listUsers) {
        if (userInfoPtr->uid() == id) {
            return userInfoPtr;
        }
    }
    return nullptr;
}

UserInfoPtr LightDMHelper::findUserByName(QString strName)
{
    for (auto userInfoPtr : m_listUsers) {
        if (userInfoPtr->name() == strName) {
            return userInfoPtr;
        }
    }
    return nullptr;
}

bool LightDMHelper::hasSameUser(const UserInfoPtr userInfoPtr)
{
    for (auto user : m_listUsers) {
        if (user->uid() == userInfoPtr->uid()
            && user->name() == userInfoPtr->name()) {
            return true;
        }
    }
    return false;
}

bool LightDMHelper::hasValidUsers()
{
    if (!m_modelUsers)
        return false;
    int count = 0;
    for(int i = 0; i < m_modelUsers->rowCount(QModelIndex()); i++){
        QString name = m_modelUsers->index(i).data(QLightDM::UsersModel::NameRole).toString();
        if(m_secUser->isSecrityUser(name))
            count++;
    }
    return (bool)(count>0);
}

bool LightDMHelper::isSameUser(UserInfoPtr userA, UserInfoPtr userB)
{
    return userA->uid() == userB->uid() &&
           userA->fullName() == userB->fullName() &&
           userA->name() == userB->name() &&
           userA->lang() == userB->lang() &&
           userA->isLoggedIn() == userB->isLoggedIn() &&
           userA->headImage() == userB->headImage() &&
           userA->backGround() == userB->backGround();
}

void LightDMHelper::onUsersChanged()
{
    if (!m_modelUsers)
        return ;
    updateUsersInfo();
    Q_EMIT usersInfoChanged();
}

void LightDMHelper::updateUsersInfo()
{
    m_listUsers.clear();
    if (m_modelUsers) {
        for(int i = 0; i < m_modelUsers->rowCount(QModelIndex()); i++){
            QString name = m_modelUsers->index(i).data(QLightDM::UsersModel::NameRole).toString();
            if(m_secUser->isSecrityUser(name)) {
                std::shared_ptr<UserInfo> userInfoPtr = std::make_shared<UserInfo>();
                userInfoPtr->updateName(name);
                uid_t uid = m_modelUsers->index(i).data(QLightDM::UsersModel::UidRole).toUInt();
                userInfoPtr->updateUid(uid);
                QString strRealName = m_modelUsers->index(i).data(QLightDM::UsersModel::RealNameRole).toString();
                if (strRealName.isEmpty()) {
                    strRealName = name;
                }
                userInfoPtr->updateFullName(strRealName);
                QString strBackGround = m_modelUsers->index(i).data(QLightDM::UsersModel::BackgroundPathRole).toString();
                if (!strBackGround.isEmpty() && QFileInfo(strBackGround).exists()){
                    userInfoPtr->updateBackground(strBackGround);
                } else {
                    if (m_accountServiceHelper) {
                        strBackGround = m_accountServiceHelper->getAccountBackground(uid);
                        if (!strBackGround.isEmpty() && QFileInfo(strBackGround).exists()){
                            userInfoPtr->updateBackground(strBackGround);
                        }
                    }
                }
                QString strImgHead = m_modelUsers->index(i).data(QLightDM::UsersModel::ImagePathRole).toString();
                if (!strImgHead.isEmpty() && QFileInfo(strImgHead).exists()){
                    userInfoPtr->updateHeadImage(strImgHead);
                }

                bool isLoggedIn = m_modelUsers->index(i).data(QLightDM::UsersModel::LoggedInRole).toBool();
                userInfoPtr->updateLoggedIn(isLoggedIn);

                if (!hasSameUser(userInfoPtr)) {
                    m_listUsers.append(userInfoPtr);
                }
            }
        }
    }
    if (m_isShowManualLogin) {
        std::shared_ptr<UserInfo> userInfoPtr = std::make_shared<UserInfo>();
        userInfoPtr->updateFullName(tr("Login"));
        userInfoPtr->updateName("*login");
        if (!hasSameUser(userInfoPtr)) {
            m_listUsers.append(userInfoPtr);
        }
    }
    if (hasGuestAccountHint()) {
        std::shared_ptr<UserInfo> userInfoPtr = std::make_shared<UserInfo>();
        userInfoPtr->updateFullName(tr("Guest"));
        userInfoPtr->updateName("*guest");
        if (!hasSameUser(userInfoPtr)) {
            m_listUsers.append(userInfoPtr);
        }
    }
}

void LightDMHelper::updateSessionsInfo()
{
    if (m_sessionsModel) {
        for(int i = 0; i < m_sessionsModel->rowCount(QModelIndex()); i++){
            QString name = m_sessionsModel->index(i).data(QLightDM::SessionsModel::KeyRole).toString();
            if (!name.isEmpty()) {
                m_listSessions.append(name);
            }
        }
    }
}

QList<UserInfoPtr> LightDMHelper::getUsersInfo()
{
    return m_listUsers;
}
