<?php

declare(strict_types=1);

namespace App\Entity;

use App\Repository\EtudiantRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity(repositoryClass: EtudiantRepository::class)]
#[ORM\Table(name: 'etudiants')]
#[ORM\UniqueConstraint(name: 'UNIQ_ETUDIANT_MATRICULE', columns: ['matricule'])]
#[ORM\UniqueConstraint(name: 'UNIQ_ETUDIANT_MATRICULE_TEMPORAIRE', columns: ['matricule_temporaire'])]
#[ORM\HasLifecycleCallbacks]
class Etudiant
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private ?Ecole $ecole = null;

    #[ORM\ManyToOne]
    #[ORM\JoinColumn(onDelete: 'SET NULL')]
    private ?AnneeScolaire $anneeScolaire = null;

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

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

    #[ORM\Column(length: 120)]
    #[Assert\NotBlank]
    private ?string $nom = null;

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

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

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

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

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

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

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

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

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

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

    #[ORM\Column(options: ['default' => false])]
    private bool $aDesEnfants = false;

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

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

    #[ORM\Column(options: ['default' => false])]
    private bool $ancien = false;

    #[ORM\Column(options: ['default' => true])]
    private bool $actif = true;

    #[ORM\ManyToOne]
    #[ORM\JoinColumn(onDelete: 'SET NULL')]
    private ?Section $section = null;

    #[ORM\ManyToOne]
    #[ORM\JoinColumn(onDelete: 'SET NULL')]
    private ?Niveau $niveau = null;

    #[ORM\ManyToOne]
    #[ORM\JoinColumn(onDelete: 'SET NULL')]
    private ?Classe $classe = null;

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

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
    private ?\DateTimeImmutable $updatedAt = null;

    /**
     * @var Collection<int, ParcoursEtudiant>
     */
    #[ORM\OneToMany(mappedBy: 'etudiant', targetEntity: ParcoursEtudiant::class, cascade: ['persist'], orphanRemoval: true)]
    #[ORM\OrderBy(['principal' => 'DESC', 'createdAt' => 'DESC', 'id' => 'DESC'])]
    private Collection $parcours;

    public function __construct()
    {
        $this->parcours = new ArrayCollection();
    }

    public function getId(): ?int { return $this->id; }
    public function getEcole(): ?Ecole { return $this->ecole; }
    public function setEcole(?Ecole $ecole): static { $this->ecole = $ecole; return $this; }
    public function getAnneeScolaire(): ?AnneeScolaire { return $this->anneeScolaire; }
    public function setAnneeScolaire(?AnneeScolaire $anneeScolaire): static { $this->anneeScolaire = $anneeScolaire; return $this; }
    public function getMatricule(): ?string { return $this->matricule; }
    public function setMatricule(?string $matricule): static { $this->matricule = $this->nullableTrim($matricule); return $this; }
    public function getMatriculeTemporaire(): ?string { return $this->matriculeTemporaire; }
    public function setMatriculeTemporaire(?string $matriculeTemporaire): static { $this->matriculeTemporaire = $this->nullableTrim($matriculeTemporaire); return $this; }
    public function getNom(): ?string { return $this->nom; }
    public function setNom(string $nom): static { $this->nom = mb_strtoupper(trim($nom)); return $this; }
    public function getPrenom(): ?string { return $this->prenom; }
    public function setPrenom(?string $prenom): static { $this->prenom = $this->nullableUpper($prenom); return $this; }
    public function getNomComplet(): string { return trim(($this->prenom ?? '').' '.($this->nom ?? '')); }
    public function getSexe(): ?string { return $this->sexe; }
    public function setSexe(?string $sexe): static { $this->sexe = $this->nullableUpper($sexe); return $this; }
    public function getDateNaissance(): ?\DateTimeInterface { return $this->dateNaissance; }
    public function setDateNaissance(?\DateTimeInterface $dateNaissance): static { $this->dateNaissance = $dateNaissance; return $this; }
    public function getLieuNaissance(): ?string { return $this->lieuNaissance; }
    public function setLieuNaissance(?string $lieuNaissance): static { $this->lieuNaissance = $this->nullableTrim($lieuNaissance); return $this; }
    public function getSituationMatrimoniale(): ?string { return $this->situationMatrimoniale; }
    public function setSituationMatrimoniale(?string $situationMatrimoniale): static { $this->situationMatrimoniale = $this->nullableUpper($situationMatrimoniale); return $this; }
    public function getTelephonePrincipal(): ?string { return $this->telephonePrincipal; }
    public function setTelephonePrincipal(?string $telephonePrincipal): static { $this->telephonePrincipal = $this->nullablePhone($telephonePrincipal); return $this; }
    public function getTelephoneWhatsapp(): ?string { return $this->telephoneWhatsapp; }
    public function setTelephoneWhatsapp(?string $telephoneWhatsapp): static { $this->telephoneWhatsapp = $this->nullablePhone($telephoneWhatsapp); return $this; }
    public function getAutreContact(): ?string { return $this->autreContact; }
    public function setAutreContact(?string $autreContact): static { $this->autreContact = $this->nullableTrim($autreContact); return $this; }
    public function getEmail(): ?string { return $this->email; }
    public function setEmail(?string $email): static { $email = $this->nullableTrim($email); $this->email = $email ? mb_strtolower($email) : null; return $this; }
    public function getAdresse(): ?string { return $this->adresse; }
    public function setAdresse(?string $adresse): static { $this->adresse = $this->nullableTrim($adresse); return $this; }
    public function getADesEnfants(): bool { return $this->aDesEnfants; }
    public function isADesEnfants(): bool { return $this->aDesEnfants; }
    public function hasEnfants(): bool { return $this->aDesEnfants; }
    public function setADesEnfants(bool $aDesEnfants): static { $this->aDesEnfants = $aDesEnfants; return $this; }
    public function getJoursDisponibles(): ?string { return $this->joursDisponibles; }
    public function setJoursDisponibles(?string $joursDisponibles): static { $this->joursDisponibles = $this->nullableTrim($joursDisponibles); return $this; }
    public function getPlageHoraireSouhaitee(): ?string { return $this->plageHoraireSouhaitee; }
    public function setPlageHoraireSouhaitee(?string $plageHoraireSouhaitee): static { $this->plageHoraireSouhaitee = $this->nullableTrim($plageHoraireSouhaitee); return $this; }
    public function isAncien(): bool { return $this->ancien; }
    public function setAncien(bool $ancien): static { $this->ancien = $ancien; return $this; }
    public function isActif(): bool { return $this->actif; }
    public function setActif(bool $actif): static { $this->actif = $actif; return $this; }
    public function getSection(): ?Section { return $this->section; }
    public function setSection(?Section $section): static { $this->section = $section; return $this; }
    public function getNiveau(): ?Niveau { return $this->niveau; }
    public function setNiveau(?Niveau $niveau): static { $this->niveau = $niveau; return $this; }
    public function getClasse(): ?Classe { return $this->classe; }
    public function setClasse(?Classe $classe): static { $this->classe = $classe; return $this; }
    public function getCreatedAt(): ?\DateTimeImmutable { return $this->createdAt; }
    public function getUpdatedAt(): ?\DateTimeImmutable { return $this->updatedAt; }
    /** @return Collection<int, ParcoursEtudiant> */
    public function getParcours(): Collection { return $this->parcours; }
    /** @param iterable<ParcoursEtudiant> $parcours */
    public function setParcours(iterable $parcours): static { foreach ($this->parcours->toArray() as $item) { $this->removeParcours($item); } foreach ($parcours as $item) { $this->addParcours($item); } return $this; }
    public function addParcours(ParcoursEtudiant $parcours): static { if (!$this->parcours->contains($parcours)) { $this->parcours->add($parcours); $parcours->setEtudiant($this); } return $this; }
    public function removeParcours(ParcoursEtudiant $parcours): static { if ($this->parcours->removeElement($parcours) && $parcours->getEtudiant() === $this) { $parcours->setEtudiant(null); } return $this; }

    #[ORM\PrePersist]
    public function initializeTimestamps(): void { $now = new \DateTimeImmutable(); $this->createdAt ??= $now; $this->updatedAt = $now; }

    #[ORM\PreUpdate]
    public function refreshUpdatedAt(): void { $this->updatedAt = new \DateTimeImmutable(); }

    private function nullableTrim(?string $value): ?string { $value = $value !== null ? trim($value) : null; return $value !== '' ? $value : null; }
    private function nullableUpper(?string $value): ?string { $value = $this->nullableTrim($value); return $value !== null ? mb_strtoupper($value) : null; }
    private function nullablePhone(?string $value): ?string
    {
        $value = $this->nullableTrim($value);
        if ($value === null) {
            return null;
        }

        $normalized = preg_replace('/[^\d+]+/', '', $value);

        return $normalized !== '' ? $normalized : null;
    }
}
