<?php

namespace App\ClinicInvitation\Entity;

use App\Auth\Entity\User;
use App\Clinic\Entity\Clinic;
use App\Doctor\Entity\Doctor;
use App\ClinicInvitation\Repository\ClinicDoctorInvitationRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: ClinicDoctorInvitationRepository::class)]
#[ORM\Table(name: 'clinic_doctor_invitations')]
#[ORM\Index(columns: ['token'], name: 'idx_cdi_token')]
#[ORM\Index(columns: ['clinic_id'], name: 'idx_cdi_clinic')]
#[ORM\Index(columns: ['mobile'], name: 'idx_cdi_mobile')]
class ClinicDoctorInvitation
{
    public const STATUS_PENDING   = 'pending';
    public const STATUS_ACCEPTED  = 'accepted';
    public const STATUS_REJECTED  = 'rejected';
    public const STATUS_SUSPENDED = 'suspended';
    public const STATUS_REMOVED   = 'removed';

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\Column(type: 'string', length: 36, unique: true)]
    private string $uuid;

    #[ORM\ManyToOne(targetEntity: Clinic::class)]
    #[ORM\JoinColumn(name: 'clinic_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
    private Clinic $clinic;

    #[ORM\ManyToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(name: 'invited_by_id', referencedColumnName: 'id', nullable: false, onDelete: 'RESTRICT')]
    private User $invitedBy;

    #[ORM\ManyToOne(targetEntity: Doctor::class)]
    #[ORM\JoinColumn(name: 'doctor_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
    private ?Doctor $doctor = null;

    #[ORM\Column(type: 'string', length: 20)]
    private string $mobile;

    #[ORM\Column(name: 'invited_name', type: 'string', length: 255, nullable: true)]
    private ?string $invitedName = null;

    #[ORM\Column(name: 'invited_specialty', type: 'string', length: 255, nullable: true)]
    private ?string $invitedSpecialty = null;

    #[ORM\Column(type: 'string', length: 128, unique: true)]
    private string $token;

    #[ORM\Column(name: 'token_used', type: 'boolean')]
    private bool $tokenUsed = false;

    #[ORM\Column(type: 'string', length: 20)]
    private string $status = self::STATUS_PENDING;

    #[ORM\Column(name: 'invited_at', type: 'integer')]
    private int $invitedAt;

    #[ORM\Column(name: 'expires_at', type: 'integer')]
    private int $expiresAt;

    #[ORM\Column(name: 'responded_at', type: 'integer', nullable: true)]
    private ?int $respondedAt = null;

    public function __construct(Clinic $clinic, User $invitedBy, string $mobile)
    {
        $this->uuid      = \Symfony\Component\Uid\Uuid::v4()->toRfc4122();
        $this->clinic    = $clinic;
        $this->invitedBy = $invitedBy;
        $this->mobile    = $mobile;
        $this->token     = bin2hex(random_bytes(6));
        $this->invitedAt = time();
        $this->expiresAt = $this->invitedAt + 72 * 3600;
    }

    public function isUsable(): bool
    {
        return $this->status === self::STATUS_PENDING
            && !$this->tokenUsed
            && time() < $this->expiresAt;
    }

    public function markUsed(): void
    {
        $this->tokenUsed   = true;
        $this->respondedAt = time();
    }

    public function refresh(): void
    {
        $this->token     = bin2hex(random_bytes(6));
        $this->tokenUsed = false;
        $this->invitedAt = time();
        $this->expiresAt = $this->invitedAt + 72 * 3600;
        $this->status    = self::STATUS_PENDING;
    }

    public function toArray(): array
    {
        return [
            'uuid'              => $this->uuid,
            'mobile'            => $this->mobile,
            'invited_name'      => $this->invitedName,
            'invited_specialty' => $this->invitedSpecialty,
            'status'            => $this->status,
            'token_used'        => $this->tokenUsed,
            'invited_at'        => $this->invitedAt,
            'expires_at'        => $this->expiresAt,
            'responded_at'      => $this->respondedAt,
            'doctor'            => $this->doctor ? [
                'uuid' => $this->doctor->getUuid(),
                'name' => $this->doctor->getName(),
            ] : null,
        ];
    }

    public function getId(): ?int            { return $this->id; }
    public function getUuid(): string        { return $this->uuid; }
    public function getClinic(): Clinic      { return $this->clinic; }
    public function getDoctor(): ?Doctor     { return $this->doctor; }
    public function getMobile(): string      { return $this->mobile; }
    public function getToken(): string       { return $this->token; }
    public function getStatus(): string      { return $this->status; }
    public function getInvitedAt(): int      { return $this->invitedAt; }
    public function getExpiresAt(): int      { return $this->expiresAt; }
    public function isTokenUsed(): bool      { return $this->tokenUsed; }
    public function getInvitedName(): ?string      { return $this->invitedName; }
    public function getInvitedSpecialty(): ?string { return $this->invitedSpecialty; }

    public function setDoctor(?Doctor $doctor): void    { $this->doctor = $doctor; }
    public function setStatus(string $status): void     { $this->status = $status; }
    public function setInvitedName(?string $n): void    { $this->invitedName = $n; }
    public function setInvitedSpecialty(?string $s): void { $this->invitedSpecialty = $s; }
}
