<?php

namespace App\Dto\Input;

use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Dto\Output\UserGroupOutput;
use App\Entity\OrganizationalUnit;
use App\Entity\User;
use App\Entity\UserGroup;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

final class UserInput
{
    #[Assert\NotBlank]
    #[Groups('user:write')]
    #[ApiProperty(
        description: 'El nombre de usuario',
        example: 'admin'
    )]
    public ?string $username = null;

    /**
     * @var OrganizationalUnitOutput[]
     */
    #[Groups('user:write')]
    #[ApiProperty(
        description: 'Las unidades organizativas permitidas para el usuario',
        example: [],
        readableLink: false,  
        writableLink: false
    )]
    public array $allowedOrganizationalUnits = [];

    #[Assert\NotBlank(groups: ['user:post'])]
    #[Assert\Length(min: 8, groups: ['user:write', 'user:post'])]
    #[Groups('user:write')]
    #[ApiProperty(
        description: 'La contraseña del usuario (mínimo 8 caracteres)',
        example: 'password123'
    )]
    public ?string $password = null;

    #[Groups('user:write')]
    #[ApiProperty(
        description: 'La vista por defecto de grupos para el usuario',
        example: 'grid'
    )]
    public ?string $groupsView = null;

    #[Assert\NotNull]
    #[Groups('user:write')]
    #[ApiProperty(
        description: 'Si el usuario está habilitado',
        example: true
    )]
    public ?bool $enabled = true;

    /**
     * @var UserGroupOutput[]
     */
    #[Groups('user:write')]
    #[ApiProperty(
        description: 'Los grupos de usuario asignados',
        example: [],
        readableLink: false,  
        writableLink: false
    )]
    public array $userGroups = [];

    #[Assert\NotBlank(groups: ['user:reset-password'])]
    #[Groups('user:reset-password')]
    #[ApiProperty(
        description: 'La contraseña actual del usuario',
        example: 'currentpass123'
    )]
    public ?string $currentPassword = null;

    #[Assert\NotBlank(groups: ['user:reset-password'])]
    #[Assert\Length(min: 8, groups: ['user:reset-password'])]
    #[Groups('user:reset-password')]
    #[ApiProperty(
        description: 'La nueva contraseña del usuario (mínimo 8 caracteres)',
        example: 'newpass123'
    )]
    public ?string $newPassword = null;

    #[Assert\NotBlank(groups: ['user:reset-password'])]
    #[Assert\Length(min: 8, groups: ['user:reset-password'])]
    #[Assert\Expression(expression: 'this.newPassword === this.repeatNewPassword', message: 'This value should be the same as the new password', groups: ['user:reset-password'])]
    #[Groups('user:reset-password')]
    #[ApiProperty(
        description: 'Repetir la nueva contraseña para confirmación',
        example: 'newpass123'
    )]
    public ?string $repeatNewPassword = null;

    public function __construct(?User $user = null)
    {
        if (!$user) {
            return;
        }

        $this->username = $user->getUsername();
        $this->enabled= $user->isEnabled();
        $this->groupsView = $user->getGroupsView();

        if ($user->getUserGroups()) {
            foreach ($user->getUserGroups() as $userGroup) {
                $this->userGroups[] = new UserGroupOutput($userGroup);
            }
        }

        if ($user->getAllowedOrganizationalUnits()) {
            foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) {
                $this->allowedOrganizationalUnits[] = new OrganizationalUnitOutput($allowedOrganizationalUnit);
            }
        }
    }

    public function createOrUpdateEntity(?User $user = null): User
    {
        if (!$user) {
            $user = new User();
        }

        $user->setUsername($this->username);
        $user->setEnabled($this->enabled);
        $user->setGroupsView($this->groupsView);

        foreach ($this->userGroups as $userGroup) {
            $userGroupsToAdd[] = $userGroup->getEntity();
        }
        $user->setUserGroups( $userGroupsToAdd ?? [] );

        if ($this->password !== null) {
            $user->setPassword($this->password);
        }

        foreach ($this->allowedOrganizationalUnits as $allowedOrganizationalUnit) {
            $allowedOrganizationalUnitToAdd[] = $allowedOrganizationalUnit->getEntity();
        }
        $user->setAllowedOrganizationalUnits( $allowedOrganizationalUnitToAdd ?? [] );

        if ($this->currentPassword !== null) {
            $user->setCurrentPassword($this->currentPassword);
        }

        if ($this->newPassword !== null) {
            $user->setNewPassword($this->newPassword);
        }

        if ($this->repeatNewPassword !== null) {
            $user->setRepeatNewPassword($this->repeatNewPassword);
        }

        return $user;
    }
}