<?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\BackendBundle\Model\Form;

use Ramsey\Uuid\Uuid;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

/**
 * Class UserCsvConfiguration
 *
 * @copyright  2019 Lifestyle Webconsulting GmbH
 * @link       https://www.life-style.de
 * @package Sso\BackendBundle\Model\Form
 */
class UserCsvConfiguration
{
    /**
     * @Assert\NotBlank()
     * @var string|null
     */
    private $id;

    /**
     * @Assert\NotBlank()
     * @var string|null
     */
    private $columnDelimiter = ';';

    /**
     * @Assert\NotBlank()
     * @var string|null
     */
    private $textEnclosure = '"';

    /**
     * @Assert\NotBlank()
     * @var string|null
     */
    private $encryptType = 'default';

    /**
     * @var bool|null
     */
    private $autoCreateUser = false;

    /**
     * @var bool|null
     */
    private $activateCreatedUser = false;

    /**
     * @Assert\NotNull()
     * @Assert\Valid()
     * @var UserCsvRow[]|null
     */
    private $rows;

    /**
     * UserCsvConfiguration constructor.
     */
    public function __construct()
    {
        $this->id = Uuid::uuid4()->toString();
    }

    /**
     * @Assert\Callback()
     * @param ExecutionContextInterface $context
     */
    public function validate(ExecutionContextInterface $context)
    {
        $primaryKeyColumns = ['guid', 'email', 'username'];
        $usedColumns = [];
        $hasPrimaryKey = false;
        foreach ($this->rows as $index => $row) {
            if ($row->getTargetEntity() !== 'user') {
                continue;
            }

            $pathPrefix = 'rows[' . $index . '].user';

            if (in_array($row->getUser()->getUserProperty(), $usedColumns)) {
                $context->buildViolation(
                    'Columns should only be used once.'
                )->atPath($pathPrefix . '.userProperty')->addViolation();
            }
            $usedColumns[] = $row->getUser()->getUserProperty();

            if ($row->getUser()->getPrimaryKey()) {
                if (!in_array($row->getUser()->getUserProperty(), $primaryKeyColumns)) {
                    $context->buildViolation(
                        'The primary key can only be set for ' . implode(', ', $primaryKeyColumns) . '.'
                    )->atPath($pathPrefix . '.primaryKey')->addViolation();
                }

                if ($hasPrimaryKey) {
                    $context->buildViolation(
                        'There should be only ony column marked as primary key.'
                    )->atPath($pathPrefix . '.primaryKey')->addViolation();
                    break;
                }

                $hasPrimaryKey = true;
            }
        }

        if (!$hasPrimaryKey) {
            $firstRow = reset($this->rows);
            $path = 'rows[' . $firstRow->getRowId() . ']' .
                ('user' === $firstRow->getTargetEntity() ? '.user.primaryKey' : '.targetEntity');
            $context->buildViolation('No primary key set.')->atPath($path)->addViolation();
        }
    }

    /**
     * @return string|null
     */
    public function getId(): ?string
    {
        return $this->id;
    }

    /**
     * @param string|null $id
     */
    public function setId(?string $id): void
    {
        $this->id = $id;
    }

    /**
     * @return string|null
     */
    public function getColumnDelimiter(): ?string
    {
        return $this->columnDelimiter;
    }

    /**
     * @param string|null $columnDelimiter
     */
    public function setColumnDelimiter(?string $columnDelimiter): void
    {
        $this->columnDelimiter = $columnDelimiter;
    }

    /**
     * @return string|null
     */
    public function getTextEnclosure(): ?string
    {
        return $this->textEnclosure;
    }

    /**
     * @param string|null $textEnclosure
     */
    public function setTextEnclosure(?string $textEnclosure): void
    {
        $this->textEnclosure = $textEnclosure;
    }

    /**
     * @return string|null
     */
    public function getEncryptType(): ?string
    {
        return $this->encryptType;
    }

    /**
     * @param string|null $encryptType
     */
    public function setEncryptType(?string $encryptType): void
    {
        $this->encryptType = $encryptType;
    }

    /**
     * @return bool|null
     */
    public function getAutoCreateUser(): ?bool
    {
        return $this->autoCreateUser;
    }

    /**
     * @param bool|null $autoCreateUser
     */
    public function setAutoCreateUser(?bool $autoCreateUser): void
    {
        $this->autoCreateUser = $autoCreateUser;
    }

    /**
     * @return bool|null
     */
    public function getActivateCreatedUser(): ?bool
    {
        return $this->activateCreatedUser;
    }

    /**
     * @param bool|null $activateCreatedUser
     */
    public function setActivateCreatedUser(?bool $activateCreatedUser): void
    {
        $this->activateCreatedUser = $activateCreatedUser;
    }

    /**
     * @return UserCsvRow[]|null
     */
    public function getRows(): ?array
    {
        usort($this->rows, function (UserCsvRow $a, UserCsvRow $b) {
            if ($a->getRowId() === $b->getRowId()) {
                return 0;
            }
            return $a->getRowId() < $b->getRowId() ? -1 : 1;
        });
        return $this->rows;
    }

    /**
     * @param UserCsvRow[]|null $rows
     */
    public function setRows(?array $rows): void
    {
        $this->rows = $rows;
    }
}
