<?php

/**
 * Lifestyle Webconsulting GmbH
 *
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is private by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @copyright  2019 Lifestyle Webconsulting GmbH
 * @link       https://www.life-style.de
 */

namespace Sso\WebserviceBundle\Api\Mapper;

use Psr\Log\LoggerInterface;
use Sso\WebserviceBundle\Database\Webservice\UserGroup as UserGroupRepository;
use Sso\WebserviceBundle\Entity\Webservice\Type\User;
use Sso\WebserviceBundle\Entity\Webservice\Type\UserGroup;

/**
 * Class UserGroupMapper
 *
 * @copyright  2019 Lifestyle Webconsulting GmbH
 * @link       https://www.life-style.de
 * @package Sso\WebserviceBundle\Api\Mapper
 */
class UserGroupMapper
{
    /**
     * @var UserGroupRepository
     */
    private $userGroupRepository;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * UserGroupMapper constructor.
     * @param UserGroupRepository $userGroupRepository
     * @param LoggerInterface $logger
     */
    public function __construct(UserGroupRepository $userGroupRepository, LoggerInterface $logger)
    {
        $this->userGroupRepository = $userGroupRepository;
        $this->logger = $logger;
    }

    /**
     * Synchronizes user groups in user entity to list of user-group-names
     * Non existing user groups will be created on the fly!
     *
     * @param User $user
     * @param array|null $userGroupNames
     * @return User
     */
    public function syncUserGroupsByNames(User $user, ?array $userGroupNames): User
    {
        if (null !== $userGroupNames) {
            // Make user group list unique - case insensitive
            $lowerUserGroups = array_unique(array_map('strtolower', $userGroupNames));
            $userGroupNames = array_intersect_key($userGroupNames, array_unique($lowerUserGroups));

            foreach ($user->getUserGroups() as $userGroup) {
                if (!in_array($userGroup->getLowerName(), $lowerUserGroups)) {
                    $user->removeUserGroup($userGroup);
                }
            }

            foreach ($userGroupNames as $userGroupName) {
                if (!$this->hasUserGroup($user, $userGroupName)) {
                    $user->addUserGroup($this->getUserGroup($userGroupName));
                }
            }
        }

        return $user;
    }

    /**
     * @param User $user
     * @param string $userGroupName
     * @return bool
     */
    private function hasUserGroup(User $user, string $userGroupName): bool
    {
        foreach ($user->getUserGroups() as $userGroup) {
            if (0 === strcasecmp($userGroup->getLowerName(), $userGroupName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param string $userGroupName
     * @return UserGroup
     */
    private function getUserGroup(string $userGroupName): UserGroup
    {
        $userGroup = $this->userGroupRepository->findByUserGroupName($userGroupName);

        // User group does not exist - create
        if (null === $userGroup) {
            $userGroup = $this->userGroupRepository->createUserGroup();
            $userGroup->setName($userGroupName);
            $this->userGroupRepository->saveUserGroup($userGroup);

            $this->logger->info(sprintf(
                'Auto create new user-group "%s" (id: %d)',
                $userGroup->getName(),
                $userGroup->getId()
            ));
        }

        return $userGroup;
    }
}
