<?php

/*
 * This file is part of the Serenity package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Serenity\SaasBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Serenity\AuthBundle\Domain\User\Entity\Profile;
use Serenity\CoreBundle\Shared\Aggregate\AggregateRoot;
use Serenity\CoreBundle\Shared\Aggregate\AggregateRootInterface;
use Serenity\CoreBundle\Shared\Common\IdentifierTrait;
use Serenity\CoreBundle\Shared\Common\TimestampTrait;
use Serenity\CoreBundle\Shared\Common\UserInterface;
use Serenity\CoreBundle\Shared\Feature\SoftDeletableTrait;
use Serenity\CoreBundle\Shared\ValueObject\Email;
use Serenity\CoreBundle\Shared\ValueObject\Password;
use Serenity\SaasBundle\Doctrine\Repository\TenantRepository;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Table(name: 'serenity_saas_tenant')]
#[ORM\Entity(repositoryClass: TenantRepository::class)]
#[ORM\HasLifecycleCallbacks]
class Tenant implements PasswordAuthenticatedUserInterface, UserInterface, AggregateRootInterface
{
    use AggregateRoot;
    use IdentifierTrait {
        IdentifierTrait::__construct as private identifierConstruct;
    }
    use SoftDeletableTrait;
    use TimestampTrait;

    #[ORM\Embedded(class: Email::class, columnPrefix: false)]
    private Email $email;

    #[ORM\Embedded(class: Password::class, columnPrefix: false)]
    private Password $password;

    #[ORM\Column(type: Types::BOOLEAN)]
    private bool $verified = false;

    #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
    private ?\DateTime $lastLinkRequestedAt = null;

    #[ORM\Column(type: Types::INTEGER)]
    private int $lastLinkRequestedAtCount = 0;

    #[ORM\Column(type: Types::STRING, nullable: true)]
    private ?string $lastLoginIp = null;

    #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
    private ?\DateTimeInterface $lastLoginAt = null;

    /**
     * @var Collection<int, Project>
     */
    #[ORM\OneToMany(targetEntity: Project::class, mappedBy: 'tenant', cascade: ['all'])]
    #[ORM\OrderBy(['name' => 'ASC'])]
    private Collection $projects;

    #[Assert\Valid]
    #[ORM\OneToOne(targetEntity: Profile::class)]
    private ?Profile $profile = null;

    /** @param non-empty-string $email */
    public function __construct(string $email, string $password, bool $test = false)
    {
        $this->identifierConstruct();
        $this->email = new Email($email);
        $this->password = new Password($password, $test);
        $this->projects = new ArrayCollection();
    }

    public function getEmail(): Email
    {
        return $this->email;
    }

    public function getUserIdentifier(): string
    {
        return $this->email->value;
    }

    public function setPassword(string $plainPassword): Password
    {
        $this->password = new Password($plainPassword);

        return $this->password;
    }

    public function getPassword(): ?string
    {
        return $this->password->value;
    }

    public function getRoles(): array
    {
        $roles[] = 'ROLE_TENANT';

        return array_unique($roles);
    }

    public function isVerified(): bool
    {
        return $this->verified;
    }

    public function setVerified(bool $verified): void
    {
        $this->verified = $verified;
    }

    public function getLastLinkRequestedAt(): ?\DateTime
    {
        return $this->lastLinkRequestedAt;
    }

    public function setLastLinkRequestedAt(?\DateTime $lastLinkRequestedAt): void
    {
        $this->lastLinkRequestedAt = $lastLinkRequestedAt;
    }

    public function getLastLinkRequestedAtCount(): int
    {
        return $this->lastLinkRequestedAtCount;
    }

    public function setLastLinkRequestedAtCount(int $lastLinkRequestedAtCount): void
    {
        $this->lastLinkRequestedAtCount = $lastLinkRequestedAtCount;
    }

    public function setLastLoginIp(?string $lastLoginIp): void
    {
        $this->lastLoginIp = $lastLoginIp;
    }

    public function setLastLoginAt(?\DateTimeInterface $lastLoginAt): void
    {
        $this->lastLoginAt = $lastLoginAt;
    }

    public function getLastLoginIp(): ?string
    {
        return $this->lastLoginIp;
    }

    public function getLastLoginAt(): ?\DateTimeInterface
    {
        return $this->lastLoginAt;
    }

    public function eraseCredentials(): void
    {
    }

    public function getSalt(): ?string
    {
        return null;
    }

    /**
     * @return Collection<int, Project>
     */
    public function getProjects(): Collection
    {
        return $this->projects;
    }

    public function addProject(Project $project): void
    {
        if ($this->projects->contains($project)) {
            return;
        }
        $project->setTenant($this);
        $this->projects->add($project);
    }

    public function removeProject(Project $project): void
    {
        if (!$this->projects->contains($project)) {
            return;
        }

        $this->projects->removeElement($project);
    }

    public function getProfile(): ?Profile
    {
        return $this->profile;
    }

    public function setProfile(?Profile $profile): void
    {
        $this->profile = $profile;
    }
}
