<?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  2018 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace Sso\WebserviceBundle\Services\UserApplicationAttribute\Add;

use Sso\WebserviceBundle\Api\Exception\Type\Api;
use Sso\WebserviceBundle\Entity\Webservice\Type\Attribute;
use Sso\WebserviceBundle\Entity\Webservice\Type\UserApplicationAttribute;
use Sso\WebserviceBundle\Services\UserApplicationAttribute\Add\Request\AttributeTypeInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;

/**
 * Class ListHandler
 *
 * @copyright  2018 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 * @package Sso\WebserviceBundle\Services\UserApplicationAttribute\Add
 */
class ApplicationAttributeListHandler
{
    /**
     * @var ValidatorInterface
     */
    private $validator;

    /**
     * @var Attribute[]
     */
    private $applicationAttributes = [];

    /**
     * @var UserApplicationAttribute[]
     */
    private $userAttributes = [];

    /**
     * @var AttributeTypeInterface[]
     */
    private $userUpdateAttributes = [];

    /**
     * ApplicationAttributeListHandler constructor.
     * @param ValidatorInterface $validator
     * @param Attribute[] $applicationAttributes
     * @param UserApplicationAttribute[] $userAttributes
     * @param UserApplicationAttribute[] $userUpdateAttributes
     */
    private function __construct(
        ValidatorInterface $validator,
        $applicationAttributes,
        $userAttributes,
        $userUpdateAttributes
    ) {
        $this->validator = $validator;

        foreach ($applicationAttributes as $attribute) {
            $this->addApplicationAttribute($attribute);
        }

        foreach ($userAttributes as $attribute) {
            $this->addUserAttribute($attribute);
        }

        foreach ($userUpdateAttributes as $attribute) {
            $this->addUserUpdateAttribute($attribute);
        }
    }

    /**
     * @param Attribute $attribute
     */
    private function addApplicationAttribute(Attribute $attribute): void
    {
        $this->applicationAttributes[] = $attribute;
    }

    /**
     * @param UserApplicationAttribute $attribute
     */
    private function addUserAttribute(UserApplicationAttribute $attribute): void
    {
        $this->userAttributes[] = $attribute;
    }

    /**
     * @param AttributeTypeInterface $attribute
     */
    private function addUserUpdateAttribute(AttributeTypeInterface $attribute): void
    {
        $this->userUpdateAttributes[] = $attribute;
    }

    /**
     * @param ValidatorInterface $validator
     * @param Attribute[] $applicationAttributes
     * @param UserApplicationAttribute[] $userAttributes
     * @param UserApplicationAttribute[] $userUpdateAttributes
     * @return ApplicationAttributeListHandler
     */
    public static function create(
        ValidatorInterface $validator,
        $applicationAttributes,
        $userAttributes,
        $userUpdateAttributes
    ): ApplicationAttributeListHandler {
        return new self($validator, $applicationAttributes, $userAttributes, $userUpdateAttributes);
    }

    /**
     * @return Attribute[]
     */
    public function getNewAttributes(): array
    {
        $attributeNames = [];
        foreach ($this->applicationAttributes as $attribute) {
            $attributeNames[] = strtolower($attribute->getName());
        }

        $newAttributes = [];
        $newAttributeNames = [];
        foreach ($this->userUpdateAttributes as $userUpdateAttribute) {
            $lowerAttributeName = strtolower($userUpdateAttribute->getName());
            if (
                !in_array($lowerAttributeName, $attributeNames) &&
                !in_array($lowerAttributeName, $newAttributeNames)
            ) {
                $attribute = new Attribute($this->validator);
                try {
                    $attribute->generateId();
                } catch (Api $exception) {
                    unset($exception);
                }
                $attribute->setName($userUpdateAttribute->getName());
                $attribute->setType($userUpdateAttribute->getType());

                $newAttributes[] = $attribute;
                $newAttributeNames[] = $lowerAttributeName;
            }
        }

        return $newAttributes;
    }

    /**
     * @return UserApplicationAttribute[]
     */
    public function getDeletedUserApplicationAttributes(): array
    {
        $updateAttributeNames = array_unique(array_map(
            function (AttributeTypeInterface $userAttribute) {
                return strtolower($userAttribute->getName());
            },
            $this->userUpdateAttributes
        ));

        $deletedAttributes = [];
        foreach ($this->userAttributes as $userAttribute) {
            $lowerUserAttributeName = strtolower($userAttribute->getName());
            if (
                in_array($lowerUserAttributeName, $updateAttributeNames) &&
                !$this->hasUserApplicationAttribute($this->userUpdateAttributes, $userAttribute)
            ) {
                $deletedAttributes[] = $userAttribute;
            }
        }

        return $deletedAttributes;
    }

    /**
     * @param UserApplicationAttribute[] $userAttributes
     * @param AttributeTypeInterface $userApplicationAttribute
     * @return bool
     */
    private function hasUserApplicationAttribute(
        array $userAttributes,
        AttributeTypeInterface $userApplicationAttribute
    ): bool {
        $lowerAttributeName = strtolower($userApplicationAttribute->getName());
        $attributeValue = $userApplicationAttribute->getValue();
        foreach ($userAttributes as $userAttribute) {
            if (
                $lowerAttributeName === strtolower($userAttribute->getName()) &&
                $attributeValue === $userAttribute->getValue()
            ) {
                return true;
            }
        }
        return false;
    }

    /**
     * @return UserApplicationAttribute[]
     */
    public function getUpdatedUserApplicationAttributes(): array
    {
        $updatedAttributes = [];
        foreach ($this->userUpdateAttributes as $userAttribute) {
            if (!$this->hasUserApplicationAttribute($this->userAttributes, $userAttribute)) {
                $updatedAttribute = new UserApplicationAttribute($this->validator);
                try {
                    $updatedAttribute->generateId();
                } catch (Api $exception) {
                    unset($exception);
                }
                $updatedAttribute->setType($userAttribute->getType());
                $updatedAttribute->setName($userAttribute->getName());
                $updatedAttribute->setValue($userAttribute->getValue());

                $updatedAttributes[] = $updatedAttribute;
            }
        }

        return $updatedAttributes;
    }
}
