<?php


class UsersList
{
    public function getUsersList(UsersListRequestStructure $data)
    {

        if (!$data->validate()) {
            return false;
        }

        switch ($data->getUserType()) {
            case 'internal':
                return $this->getInternalUsersList($data);
                break;
            case 'external':
                return $this->getExternalUsersList($data);
                break;
        }

    }

    private function getInternalUsersList(UsersListRequestStructure $data)
    {
        $cfdb = CfSettings::getInstance()->getConnection();

        //page - 1 because it starts from 1
        $offset    = ($data->getPage() - 1) * $data->getCount();
        $where     = '';
        $bindParams = ['limit' => $data->getCount(), ':offset' => $offset];
        if (!$data->getUserNameRx() == null) {
            $where = "WHERE username LIKE :username";
            $bindParams[':username'] = '%'. $data->getUserNameRx() .'%';
        }

        $locked = $data->isTwoFaEnforced() ? "COALESCE((now() > first_login_after_2fa_enforced + INTERVAL '48 hours' AND two_factor_enabled IS FALSE), FALSE)" : 'FALSE';
        $dataQuery = sprintf(
            'SELECT email, external, username AS id, array_to_json(roles) AS roles, two_factor_enabled, %s AS locked FROM users %s LIMIT :limit OFFSET :offset',
            $locked,
            $where
        );
        $stmt      = $cfdb->prepare($dataQuery);
        $stmt->execute($bindParams);
        $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
        //transform roles from string to array
        array_walk($users, function (&$user) {
            $user['roles'] = json_decode($user['roles'], JSON_OBJECT_AS_ARRAY);
        });

        $meta = [
            "count"     => count($users),
            "page"      => $data->getPage(),
            "timestamp" => time(),
            "total"     => $this->getAllUsersCount()
        ];
        $response = [ 'data' => $users, 'meta' => $meta ];

        return json_encode($response);
    }

    private function getAllUsersCount()
    {
        $cfdb       = CfSettings::getInstance()->getConnection();
        $countQuery = 'SELECT COUNT(*) AS total FROM users';
        $count      = $cfdb->query($countQuery)->fetch(PDO::FETCH_ASSOC);

        return $count['total'];
    }

    private function getExternalUsersList(UsersListRequestStructure $data)
    {
        $ldapApiUrl = LDAP_API_URL;
        if (!$ldapApiUrl) {
            throw new Exception('To get external users list you need to setup LDAP authentication settings');
        }

        /**
         * @var Pest $pestClient
         */
        $pestClient = new Pest($ldapApiUrl);

        $ldapUsers = $pestClient->get('/users?' . http_build_query(['page' => $data->getPage(), 'perPage' => $data->getCount(), 'search' => $data->getUserNameRx()]), ['Authorization: ' . LDAP_API_SECRET_KEY]);

        return $this->combineLdapWithCFengineUsers($data, $ldapUsers);
        ;
    }

    private function combineLdapWithCFengineUsers(UsersListRequestStructure $data, $ldapUsers)
    {
        $data->setPage(1);
        $data->setCount(1000);
        $cfengineUsers  = json_decode($this->getInternalUsersList($data), JSON_OBJECT_AS_ARRAY);
        $ldapUsersArray = json_decode($ldapUsers);

        if (isset($ldapUsersArray->data)) {
            foreach ($ldapUsersArray->data as $key => $user) {
                $ldapUsersArray->data[$key]->isLogged = false;
                $ldapUsersArray->data[$key]->external = true;
                $id = array_search($user->id, array_column($cfengineUsers['data'], 'id'));
                $ldapUsersArray->data[$key]->ldapGroups = $ldapUsersArray->data[$key]->roles;
                $ldapUsersArray->data[$key]->roles = [];
                if ($id !== false) {
                    $ldapUsersArray->data[$key]->isLogged = true;
                    $ldapUsersArray->data[$key]->roles = $cfengineUsers['data'][$id]['roles'];
                    $ldapUsersArray->data[$key]->ldapGroups = array_values(
                        array_diff($ldapUsersArray->data[$key]->ldapGroups, $ldapUsersArray->data[$key]->roles)
                    );
                }
            }
            return json_encode($ldapUsersArray, JSON_PRETTY_PRINT);
        } else {
            return $ldapUsers;
        }
    }

}
