<?php

declare(strict_types=1);

namespace App\Entity;

use App\Repository\InscriptionRepository;
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: InscriptionRepository::class)]
#[ORM\Table(name: 'inscriptions')]
#[ORM\UniqueConstraint(name: 'UNIQ_INSCRIPTION_NUMERO_DOSSIER', columns: ['numero_dossier'])]
#[ORM\HasLifecycleCallbacks]
class Inscription
{
    public const TYPE_NOUVEAU = 'NOUVEAU';
    public const TYPE_ANCIEN = 'ANCIEN';

    public const STATUT_SOUMISE = 'SOUMISE';
    public const STATUT_A_TESTER = 'A_TESTER';
    public const STATUT_A_AFFECTER = 'A_AFFECTER';
    public const STATUT_VALIDEE = 'VALIDEE';
    public const STATUT_REJETEE = 'REJETEE';
    public const STATUT_ANNULEE = 'ANNULEE';

    #[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\ManyToOne]
    #[ORM\JoinColumn(onDelete: 'SET NULL')]
    private ?Etudiant $etudiant = null;

    #[ORM\Column(length: 50, unique: true)]
    private ?string $numeroDossier = null;

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

    #[ORM\Column(length: 20)]
    private string $typeCandidat = self::TYPE_NOUVEAU;

    #[ORM\Column(length: 40, nullable: true)]
    private ?string $ancienMatricule = 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\ManyToOne]
    #[ORM\JoinColumn(onDelete: 'SET NULL')]
    private ?Section $sectionSouhaitee = null;

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

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

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

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

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

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

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

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

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

    #[ORM\Column(length: 30)]
    private string $statut = self::STATUT_SOUMISE;

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

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

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

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

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

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

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

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

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

    /**
     * @var Collection<int, InscriptionParcours>
     */
    #[ORM\OneToMany(mappedBy: 'inscription', targetEntity: InscriptionParcours::class, cascade: ['persist'], orphanRemoval: true)]
    #[ORM\OrderBy(['principal' => 'DESC', 'ordre' => 'ASC', 'id' => 'ASC'])]
    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 getEtudiant(): ?Etudiant { return $this->etudiant; }
    public function setEtudiant(?Etudiant $etudiant): static { $this->etudiant = $etudiant; return $this; }
    public function getNumeroDossier(): ?string { return $this->numeroDossier; }
    public function setNumeroDossier(string $numeroDossier): static { $this->numeroDossier = trim($numeroDossier); return $this; }
    public function getMatriculeTemporaire(): ?string { return $this->matriculeTemporaire; }
    public function setMatriculeTemporaire(?string $matriculeTemporaire): static { $this->matriculeTemporaire = $this->nullableTrim($matriculeTemporaire); return $this; }
    public function getDisplayMatricule(): ?string { return $this->etudiant?->getMatricule() ?: $this->ancienMatricule ?: $this->matriculeTemporaire; }
    public function getTypeCandidat(): string { return $this->typeCandidat; }
    public function setTypeCandidat(string $typeCandidat): static { $this->typeCandidat = mb_strtoupper(trim($typeCandidat)); return $this; }
    public function getAncienMatricule(): ?string { return $this->ancienMatricule; }
    public function setAncienMatricule(?string $ancienMatricule): static { $this->ancienMatricule = $this->nullableTrim($ancienMatricule); return $this; }
    public function getNom(): ?string { return $this->nom; }
    public function setNom(string $nom): static { $this->nom = trim($nom); return $this; }
    public function getPrenom(): ?string { return $this->prenom; }
    public function setPrenom(?string $prenom): static { $this->prenom = $this->nullableTrim($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 getSectionSouhaitee(): ?Section { return $this->sectionSouhaitee; }
    public function setSectionSouhaitee(?Section $sectionSouhaitee): static { $this->sectionSouhaitee = $sectionSouhaitee; return $this; }
    public function getNiveauSouhaite(): ?Niveau { return $this->niveauSouhaite; }
    public function setNiveauSouhaite(?Niveau $niveauSouhaite): static { $this->niveauSouhaite = $niveauSouhaite; return $this; }
    public function getClasseSouhaitee(): ?Classe { return $this->classeSouhaitee; }
    public function setClasseSouhaitee(?Classe $classeSouhaitee): static { $this->classeSouhaitee = $classeSouhaitee; return $this; }
    public function getSectionFinale(): ?Section { return $this->sectionFinale; }
    public function setSectionFinale(?Section $sectionFinale): static { $this->sectionFinale = $sectionFinale; return $this; }
    public function getNiveauFinal(): ?Niveau { return $this->niveauFinal; }
    public function setNiveauFinal(?Niveau $niveauFinal): static { $this->niveauFinal = $niveauFinal; return $this; }
    public function getClasseFinale(): ?Classe { return $this->classeFinale; }
    public function setClasseFinale(?Classe $classeFinale): static { $this->classeFinale = $classeFinale; return $this; }
    public function getLangueSouhaitee(): ?string { return $this->langueSouhaitee; }
    public function setLangueSouhaitee(?string $langueSouhaitee): static { $this->langueSouhaitee = $this->nullableUpper($langueSouhaitee); return $this; }
    public function getModeSouhaite(): ?string { return $this->modeSouhaite; }
    public function setModeSouhaite(?string $modeSouhaite): static { $this->modeSouhaite = $this->nullableUpper($modeSouhaite); return $this; }
    public function getObservationCandidat(): ?string { return $this->observationCandidat; }
    public function setObservationCandidat(?string $observationCandidat): static { $this->observationCandidat = $this->nullableTrim($observationCandidat); return $this; }
    public function getObservationAdmin(): ?string { return $this->observationAdmin; }
    public function setObservationAdmin(?string $observationAdmin): static { $this->observationAdmin = $this->nullableTrim($observationAdmin); return $this; }
    public function getStatut(): string { return $this->statut; }
    public function setStatut(string $statut): static { $this->statut = mb_strtoupper(trim($statut)); return $this; }
    public function isSoumise(): bool { return $this->statut === self::STATUT_SOUMISE; }
    public function isATester(): bool { return $this->statut === self::STATUT_A_TESTER; }
    public function isAAffecter(): bool { return $this->statut === self::STATUT_A_AFFECTER; }
    public function isValidee(): bool { return $this->statut === self::STATUT_VALIDEE; }
    public function isRejetee(): bool { return $this->statut === self::STATUT_REJETEE; }
    public function isAnnulee(): bool { return $this->statut === self::STATUT_ANNULEE; }
    public function canBeMarkedForTest(): bool { return in_array($this->statut, [self::STATUT_SOUMISE, self::STATUT_A_AFFECTER], true); }
    public function canBeAssigned(): bool { return in_array($this->statut, [self::STATUT_SOUMISE, self::STATUT_A_TESTER, self::STATUT_A_AFFECTER], true); }
    public function canBeValidated(): bool { return in_array($this->statut, [self::STATUT_SOUMISE, self::STATUT_A_TESTER, self::STATUT_A_AFFECTER], true); }
    public function canBeRejected(): bool { return in_array($this->statut, [self::STATUT_SOUMISE, self::STATUT_A_TESTER, self::STATUT_A_AFFECTER], true); }
    public function canBeDeleted(): bool { return !$this->isValidee(); }
    public function getMotifRejet(): ?string { return $this->motifRejet; }
    public function setMotifRejet(?string $motifRejet): static { $this->motifRejet = $this->nullableTrim($motifRejet); return $this; }
    public function getFichePdfPath(): ?string { return $this->fichePdfPath; }
    public function setFichePdfPath(?string $fichePdfPath): static { $this->fichePdfPath = $this->nullableTrim($fichePdfPath); return $this; }
    public function getWhatsappNotificationSentAt(): ?\DateTimeImmutable { return $this->whatsappNotificationSentAt; }
    public function setWhatsappNotificationSentAt(?\DateTimeImmutable $whatsappNotificationSentAt): static { $this->whatsappNotificationSentAt = $whatsappNotificationSentAt; return $this; }
    public function getWhatsappLastError(): ?string { return $this->whatsappLastError; }
    public function setWhatsappLastError(?string $whatsappLastError): static { $this->whatsappLastError = $this->nullableTrim($whatsappLastError); return $this; }
    public function getDateSoumission(): ?\DateTimeImmutable { return $this->dateSoumission; }
    public function setDateSoumission(?\DateTimeImmutable $dateSoumission): static { $this->dateSoumission = $dateSoumission; return $this; }
    public function getDateValidation(): ?\DateTimeImmutable { return $this->dateValidation; }
    public function setDateValidation(?\DateTimeImmutable $dateValidation): static { $this->dateValidation = $dateValidation; return $this; }
    public function getDateRejet(): ?\DateTimeImmutable { return $this->dateRejet; }
    public function setDateRejet(?\DateTimeImmutable $dateRejet): static { $this->dateRejet = $dateRejet; return $this; }
    public function getCreatedAt(): ?\DateTimeImmutable { return $this->createdAt; }
    public function getUpdatedAt(): ?\DateTimeImmutable { return $this->updatedAt; }
    /** @return Collection<int, InscriptionParcours> */
    public function getParcours(): Collection { return $this->parcours; }
    /** @param iterable<InscriptionParcours> $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(InscriptionParcours $parcours): static { if (!$this->parcours->contains($parcours)) { $this->parcours->add($parcours); $parcours->setInscription($this); } return $this; }
    public function removeParcours(InscriptionParcours $parcours): static { if ($this->parcours->removeElement($parcours) && $parcours->getInscription() === $this) { $parcours->setInscription(null); } return $this; }

    #[ORM\PrePersist]
    public function initializeTimestamps(): void
    {
        $now = new \DateTimeImmutable();
        $this->createdAt ??= $now;
        $this->updatedAt = $now;
        $this->dateSoumission ??= $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;
    }
}
