<?php

namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: 'users')]
#[ORM\UniqueConstraint(name: 'uniq_user_email', columns: ['email'])]
class User implements UserInterface
{
    // ─── Groupes (rôles métier) ───
    public const ROLE_ADMIN = 'ROLE_ADMIN';
    public const ROLE_AUDIT = 'ROLE_AUDIT';
    public const ROLE_SUPERVISEUR = 'ROLE_SUPERVISEUR';
    public const ROLE_OPERATEUR = 'ROLE_OPERATEUR';
    public const ROLE_LECTEUR = 'ROLE_LECTEUR';

    /** Groupes assignables (ordre = puissance décroissante). */
    public const GROUPS = [
        self::ROLE_ADMIN,
        self::ROLE_AUDIT,
        self::ROLE_SUPERVISEUR,
        self::ROLE_OPERATEUR,
        self::ROLE_LECTEUR,
    ];

    /** Groupes qu'un utilisateur peut demander lui-même à l'inscription (ADMIN exclu). */
    public const REQUESTABLE_GROUPS = [
        self::ROLE_AUDIT,
        self::ROLE_SUPERVISEUR,
        self::ROLE_OPERATEUR,
        self::ROLE_LECTEUR,
    ];

    public const GROUP_LABELS = [
        self::ROLE_ADMIN => 'Administrateur',
        self::ROLE_AUDIT => 'Audit',
        self::ROLE_SUPERVISEUR => 'Superviseur',
        self::ROLE_OPERATEUR => 'Opérateur saisie',
        self::ROLE_LECTEUR => 'Lecteur',
    ];

    // ─── Statuts du compte ───
    public const STATUS_ONBOARDING = 'onboarding'; // créé, doit choisir groupe + concessions
    public const STATUS_PENDING = 'pending';       // demande soumise, en attente de validation
    public const STATUS_ACTIVE = 'active';         // validé
    public const STATUS_REFUSED = 'refused';       // demande refusée

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 180)]
    private string $email;

    /** @var list<string> */
    #[ORM\Column(type: Types::JSON)]
    private array $roles = [];

    /** @var list<string> Concessions de l'utilisateur (périmètre de visibilité + export) */
    #[ORM\Column(type: Types::JSON)]
    private array $concessions = [];

    #[ORM\Column(length: 16, options: ['default' => self::STATUS_ONBOARDING])]
    private string $status = self::STATUS_ONBOARDING;

    /** Groupe demandé lors de l'inscription (avant validation). */
    #[ORM\Column(length: 32, nullable: true)]
    private ?string $requestedRole = null;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
    private ?\DateTimeImmutable $validatedAt = null;

    #[ORM\Column(length: 180, nullable: true)]
    private ?string $validatedBy = null;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
    private \DateTimeImmutable $createdAt;

    public function __construct(string $email)
    {
        $this->email = $email;
        $this->createdAt = new \DateTimeImmutable();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

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

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

    /** @return list<string> */
    public function getRoles(): array
    {
        $roles = $this->roles;
        $roles[] = 'ROLE_USER';

        return array_values(array_unique($roles));
    }

    /** @param list<string> $roles */
    public function setRoles(array $roles): static
    {
        $this->roles = array_values($roles);

        return $this;
    }

    /**
     * Définit l'unique groupe métier de l'utilisateur (remplace les rôles existants).
     */
    public function setGroup(string $role): static
    {
        if (!\in_array($role, self::GROUPS, true)) {
            throw new \InvalidArgumentException(sprintf('Groupe invalide : %s', $role));
        }
        $this->roles = [$role];

        return $this;
    }

    /** Premier groupe métier connu, ou null. */
    public function getGroup(): ?string
    {
        foreach (self::GROUPS as $g) {
            if (\in_array($g, $this->roles, true)) {
                return $g;
            }
        }

        return null;
    }

    public function getGroupLabel(): string
    {
        $g = $this->getGroup();

        return null !== $g ? (self::GROUP_LABELS[$g] ?? $g) : '—';
    }

    /** ADMIN et AUDIT voient toutes les concessions. */
    public function seesAllConcessions(): bool
    {
        return \in_array(self::ROLE_ADMIN, $this->roles, true)
            || \in_array(self::ROLE_AUDIT, $this->roles, true);
    }

    /**
     * Périmètre de concessions pour les requêtes :
     * null = aucune restriction (voit tout), sinon la liste des concessions de l'utilisateur.
     * Un compte non actif ne voit RIEN (défense en profondeur, en complément du gate d'onboarding) :
     * tant qu'il n'est pas validé, ses concessions « demandées » ne doivent pas filtrer de scans.
     *
     * @return list<string>|null
     */
    public function scopeConcessions(): ?array
    {
        if (!$this->isActive()) {
            return []; // aucun périmètre → aucun résultat
        }

        return $this->seesAllConcessions() ? null : $this->concessions;
    }

    /** @return list<string> */
    public function getConcessions(): array
    {
        return $this->concessions;
    }

    /** @param array<string> $concessions */
    public function setConcessions(array $concessions): static
    {
        $this->concessions = array_values($concessions);

        return $this;
    }

    public function getStatus(): string
    {
        return $this->status;
    }

    public function setStatus(string $status): static
    {
        $this->status = $status;

        return $this;
    }

    public function isActive(): bool
    {
        return self::STATUS_ACTIVE === $this->status;
    }

    public function getRequestedRole(): ?string
    {
        return $this->requestedRole;
    }

    public function setRequestedRole(?string $requestedRole): static
    {
        $this->requestedRole = $requestedRole;

        return $this;
    }

    public function getValidatedAt(): ?\DateTimeImmutable
    {
        return $this->validatedAt;
    }

    public function setValidatedAt(?\DateTimeImmutable $validatedAt): static
    {
        $this->validatedAt = $validatedAt;

        return $this;
    }

    public function getValidatedBy(): ?string
    {
        return $this->validatedBy;
    }

    public function setValidatedBy(?string $validatedBy): static
    {
        $this->validatedBy = $validatedBy;

        return $this;
    }

    public function getCreatedAt(): \DateTimeImmutable
    {
        return $this->createdAt;
    }

    public function eraseCredentials(): void
    {
        // Aucune donnée sensible en mémoire (auth par OTP, pas de mot de passe).
    }
}
