<?php

namespace App\Clinic\Entity;

use App\Auth\Entity\User;
use App\Doctor\Entity\Doctor;
use App\DoctorService\Entity\DoctorService;
use App\Insurance\Entity\Insurance;
use App\Specialty\Entity\Specialty;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Clinic\Repository\ClinicRepository;
use Symfony\Component\Uid\Uuid;

#[ORM\Entity(repositoryClass: ClinicRepository::class)]
#[ORM\Table(name: 'clinics')]
#[ORM\Index(columns: ['user_id'], name: 'idx_clinics_owner')]
#[ORM\Index(columns: ['city_id'], name: 'idx_clinics_city')]
#[ORM\Index(columns: ['province_id'], name: 'idx_clinics_province')]
class Clinic
{
    #[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: User::class)]
    #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: false, onDelete: 'RESTRICT')]
    private User $user;

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

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $info = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $address = null;

    #[ORM\Column(type: 'string', length: 50, nullable: true)]
    private ?string $telephone = null;

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

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

    #[ORM\Column(type: 'float', nullable: true)]
    private ?float $latitude = null;

    #[ORM\Column(type: 'float', nullable: true)]
    private ?float $longitude = null;

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

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

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

    #[ORM\Column(name: 'is_active', type: 'boolean')]
    private bool $isActive = true;

    #[ORM\Column(name: 'images_clinic', type: 'json', nullable: true)]
    private ?array $imagesClinic = null;

    #[ORM\Column(name: 'social_media', type: 'json', nullable: true)]
    private ?array $socialMedia = null;

    #[ORM\Column(name: 'clinic_logo', type: 'string', length: 500, nullable: true)]
    private ?string $clinicLogo = null;

    #[ORM\Column(name: 'notification_mobile', type: 'string', length: 15, nullable: true)]
    private ?string $notificationMobile = null;

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

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

    #[ORM\ManyToMany(targetEntity: Doctor::class)]
    #[ORM\JoinTable(
        name: 'clinic_doctors',
        joinColumns: [new ORM\JoinColumn(name: 'clinic_id', referencedColumnName: 'id', onDelete: 'CASCADE')],
        inverseJoinColumns: [new ORM\JoinColumn(name: 'doctor_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
    )]
    private Collection $doctors;

    #[ORM\ManyToMany(targetEntity: Specialty::class)]
    #[ORM\JoinTable(
        name: 'clinic_specialties',
        joinColumns: [new ORM\JoinColumn(name: 'clinic_id', referencedColumnName: 'id', onDelete: 'CASCADE')],
        inverseJoinColumns: [new ORM\JoinColumn(name: 'specialty_id', referencedColumnName: 'id')]
    )]
    private Collection $specialties;

    #[ORM\ManyToMany(targetEntity: DoctorService::class)]
    #[ORM\JoinTable(
        name: 'clinic_services',
        joinColumns: [new ORM\JoinColumn(name: 'clinic_id', referencedColumnName: 'id', onDelete: 'CASCADE')],
        inverseJoinColumns: [new ORM\JoinColumn(name: 'service_id', referencedColumnName: 'id')]
    )]
    private Collection $services;

    #[ORM\ManyToMany(targetEntity: Insurance::class)]
    #[ORM\JoinTable(
        name: 'clinic_insurances',
        joinColumns: [new ORM\JoinColumn(name: 'clinic_id', referencedColumnName: 'id', onDelete: 'CASCADE')],
        inverseJoinColumns: [new ORM\JoinColumn(name: 'insurance_id', referencedColumnName: 'id')]
    )]
    private Collection $insurances;

    public function __construct(User $user)
    {
        $this->uuid        = Uuid::v4()->toRfc4122();
        $this->user        = $user;
        $this->createdAt   = time();
        $this->updatedAt   = time();
        $this->doctors     = new ArrayCollection();
        $this->specialties = new ArrayCollection();
        $this->services    = new ArrayCollection();
        $this->insurances  = new ArrayCollection();
    }

    public function getId(): ?int    { return $this->id; }
    public function getUuid(): string { return $this->uuid; }
    public function getUser(): User  { return $this->user; }
    public function getName(): ?string { return $this->name; }
    public function getInfo(): ?string { return $this->info; }
    public function getAddress(): ?string { return $this->address; }
    public function getTelephone(): ?string { return $this->telephone; }
    public function isIs247(): bool  { return $this->is247; }
    public function getWorkingDays(): ?string { return $this->workingDays; }
    public function getLatitude(): ?float { return $this->latitude; }
    public function getLongitude(): ?float { return $this->longitude; }
    public function getCityId(): ?int { return $this->cityId; }
    public function getProvinceId(): ?int { return $this->provinceId; }
    public function getRepresentationId(): ?int { return $this->representationId; }
    public function isActive(): bool            { return $this->isActive; }
    public function getImagesClinic(): ?array { return $this->imagesClinic; }
    public function getSocialMedia(): ?array  { return $this->socialMedia; }
    public function getClinicLogo(): ?string      { return $this->clinicLogo; }
    public function getNotificationMobile(): ?string { return $this->notificationMobile; }
    public function getCreatedAt(): int           { return $this->createdAt; }
    public function getUpdatedAt(): int { return $this->updatedAt; }
    public function getDoctors(): Collection    { return $this->doctors; }

    public function hasDoctor(Doctor $doctor): bool { return $this->doctors->contains($doctor); }

    public function removeDoctor(Doctor $doctor): self
    {
        $this->doctors->removeElement($doctor);
        $this->touch();
        return $this;
    }

    public function getSpecialties(): Collection { return $this->specialties; }
    public function getServices(): Collection   { return $this->services; }
    public function getInsurances(): Collection { return $this->insurances; }

    public function setName(?string $v): self       { $this->name = $v; $this->touch(); return $this; }
    public function setInfo(?string $v): self        { $this->info = $v; $this->touch(); return $this; }
    public function setAddress(?string $v): self     { $this->address = $v; $this->touch(); return $this; }
    public function setTelephone(?string $v): self   { $this->telephone = $v; $this->touch(); return $this; }
    public function setIs247(bool $v): self          { $this->is247 = $v; $this->touch(); return $this; }
    public function setWorkingDays(?string $v): self { $this->workingDays = $v; $this->touch(); return $this; }
    public function setLatitude(?float $v): self     { $this->latitude = $v; $this->touch(); return $this; }
    public function setLongitude(?float $v): self    { $this->longitude = $v; $this->touch(); return $this; }
    public function setCityId(?int $v): self         { $this->cityId = $v; $this->touch(); return $this; }
    public function setProvinceId(?int $v): self     { $this->provinceId = $v; $this->touch(); return $this; }
    public function setRepresentationId(?int $v): self { $this->representationId = $v; $this->touch(); return $this; }
    public function setIsActive(bool $v): self          { $this->isActive = $v; $this->touch(); return $this; }
    public function setImagesClinic(?array $v): self { $this->imagesClinic = $v; $this->touch(); return $this; }
    public function setSocialMedia(?array $v): self  { $this->socialMedia = $v; $this->touch(); return $this; }
    public function setClinicLogo(?string $v): self      { $this->clinicLogo = $v; $this->touch(); return $this; }
    public function setNotificationMobile(?string $v): self { $this->notificationMobile = $v; $this->touch(); return $this; }

    private function touch(): void { $this->updatedAt = time(); }

    public function toDetailArray(array $provinceData = [], array $cityData = [], ?array $map = null): array
    {
        return [
            'id'                => (string) $this->id,
            'uuid'              => $this->uuid,
            'name'              => $this->name,
            'title'             => $this->name,
            'is_active'         => $this->isActive,
            'phone'             => $this->telephone,
            'logo'              => $this->clinicLogo,
            'images_clinic'     => $this->imagesClinic ?? [],
            'social_media'      => $this->socialMedia,
            'clinic_logo'       => $this->clinicLogo,
            'phone_number'      => $this->telephone,
            'caption'           => $this->info,
            'list_bime'         => array_map(fn(Insurance $i) => [
                'uuid' => $i->getUuid(), 'id' => (string) $i->getId(), 'name' => $i->getName(),
            ], $this->insurances->toArray()),
            'specialties'       => array_map(fn(Specialty $s) => [
                'uuid' => $s->getUuid(), 'id' => (string) $s->getId(), 'name' => $s->getName(),
                'parent' => $s->getParent()?->getId() !== null ? (string) $s->getParent()->getId() : null,
            ], $this->specialties->toArray()),
            'services'          => array_map(fn(DoctorService $ds) => [
                'uuid' => $ds->getUuid(), 'id' => (string) $ds->getId(), 'name' => $ds->getName(),
            ], $this->services->toArray()),
            'clinic_specialty'  => array_map(fn(Specialty $s) => [
                'uuid' => $s->getUuid(), 'id' => (string) $s->getId(), 'name' => $s->getName(),
                'parent' => $s->getParent()?->getId() !== null ? (string) $s->getParent()->getId() : null,
            ], $this->specialties->toArray()),
            'doctors'           => $this->doctors->count(),
            'doctor_list'       => null,
            'city'              => $cityData ? [$cityData] : [],
            'state'             => $provinceData ? [$provinceData] : [],
            'location'          => $this->address,
            'map'               => $map ?? [
                'latitude'  => $this->latitude !== null ? (string) $this->latitude : null,
                'longitude' => $this->longitude !== null ? (string) $this->longitude : null,
            ],
            '24_7'              => $this->is247,
            'field_working_days' => $this->workingDays,
        ];
    }

    public function toListArray(?string $city = null, ?string $state = null): array
    {
        return [
            'id'            => (string) $this->id,
            'uuid'          => $this->uuid,
            'name'          => $this->name,
            'title'         => $this->name,
            'phone'         => $this->telephone,
            'phone_number'  => $this->telephone,
            'logo'          => $this->clinicLogo,
            'clinic_logo'   => $this->clinicLogo,
            'images_clinic' => $this->imagesClinic ?? [],
            'doctors_count' => $this->doctors->count(),
            'is_active'     => $this->isActive,
            'created_at'    => $this->createdAt,
            'city'          => $city,
            'state'         => $state,
            'specialties'   => array_map(fn(Specialty $s) => [
                'uuid' => $s->getUuid(), 'id' => (string) $s->getId(), 'name' => $s->getName(),
            ], $this->specialties->toArray()),
            '24_7'              => $this->is247,
            'field_working_days' => $this->workingDays,
        ];
    }
}
