<?php

namespace App\Entity;

use App\Repository\UserRepository;
use App\Enums\RateType;
use App\Enums\CaseLevel;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Uid\Uuid;
use Vich\UploaderBundle\Entity\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USERNAME', fields: ['username'])]
#[UniqueEntity(fields: ['username'], message: 'There is already an account with this username')]
#[Vich\Uploadable]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\Column(type: UuidType::NAME, unique: true)]
    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
    #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
    private ?Uuid $id = null;

    #[ORM\Column(length: 45)]
    private ?string $username = null;

    /**
     * @var list<string> The user roles
     */
    #[ORM\Column]
    private array $roles = [];

    /**
     * @var string The hashed password
     */
    #[ORM\Column]
    private ?string $password = null;

    #[ORM\Column(length: 45)]
    private ?string $name = null;

    #[ORM\Column(length: 64)]
    private ?string $email = null;

    #[ORM\Column(enumType: RateType::class)]
    private ?RateType $rateType = null;

    #[ORM\Column(type: Types::DECIMAL, precision: 6, scale: 2)]
    private ?string $rate = null;

    #[ORM\ManyToOne(inversedBy: 'users')]
    #[ORM\JoinColumn(nullable: true)]
    private ?Company $company = null;

    #[ORM\Column(enumType: CaseLevel::class)]
    private ?CaseLevel $level = null;

    /**
     * @var Collection<int, UserCase>
     */
    #[ORM\OneToMany(targetEntity: UserCase::class, mappedBy: 'user')]
    private Collection $userCases;

    #[Vich\UploadableField(mapping: 'profile_image', fileNameProperty: 'imageName', size: 'size', mimeType: 'mimeType', originalName: 'originalName', dimensions: 'dimensions')]
    private ?File $imageFile = null;

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

    #[ORM\Column(type: Types::DATETIME_MUTABLE)]
    private ?\DateTimeInterface $passwordChanged = null;

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

    #[ORM\Column(length: 15)]
    private ?string $workPhone = null;

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

    #[ORM\Column]
    private ?bool $active = null;

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

    private ?User $supervisor = null;

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

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

    public function getUsername(): ?string
    {
        return $this->username;
    }

    public function setUsername(string $username): static
    {
        $this->username = $username;

        return $this;
    }

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUserIdentifier(): string
    {
        return (string) $this->username;
    }

    /**
     * @see UserInterface
     *
     * @return list<string>
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

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

        return $this;
    }

    /**
     * @see PasswordAuthenticatedUserInterface
     */
    public function getPassword(): ?string
    {
        return $this->password;
    }

    public function setPassword(string $password): static
    {
        $this->password = $password;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials(): void
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): static
    {
        $this->name = $name;

        return $this;
    }

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

    public function setEmail(string $email): static
    {
        $this->email = $email;

        return $this;
    }

    public function getRateType(): ?RateType
    {
        return $this->rateType;
    }

    public function setRateType(RateType $rateType): static
    {
        $this->rateType = $rateType;

        return $this;
    }

    public function getRate(): ?string
    {
        return $this->rate;
    }

    public function setRate(string $rate): static
    {
        $this->rate = $rate;

        return $this;
    }

    /**
     * @return Collection<int, UserCase>
     */
    public function getUserCases(): Collection
    {
        return $this->userCases;
    }

    public function getCompany(): ?Company
    {
        return $this->company;
    }

    public function setCompany(?Company $company): static
    {
        $this->company = $company;

        return $this;
    }

    public function getLevel(): ?CaseLevel
    {
        return $this->level;
    }

    public function setLevel(CaseLevel $level): static
    {
        $this->level = $level;

        return $this;
    }

    public function getSupervisor(): ?User
    {
        return $this->supervisor;
    }

    public function setSupervisor(?User $supervisor): static
    {
        $this->supervisor = $supervisor;

        return $this;
    }

    public function isCaseWorker(): ?bool
    {
        return in_array('ROLE_CASE_WORKER', $this->roles);
    }

    public function isCaseManager(): ?bool
    {
        return in_array('ROLE_CASE_MANAGER', $this->roles);
    }

    public function isTherapist(): ?bool
    {
        return in_array('ROLE_THERAPIST', $this->roles);
    }

    public function isAdmin(): ?bool
    {
        return in_array('ROLE_ADMIN', $this->roles);
    }

    public function getJobs(): array
    {
        $jobs = [];
        if (in_array('ROLE_CASE_WORKER', $this->roles)) {
            $jobs[] = 'Case Worker';
        }

        if (in_array('ROLE_CASE_MANAGER', $this->roles)) {
            $jobs[] = 'Case Manager';
        }

        if (in_array('ROLE_THERAPIST', $this->roles)) {
            $jobs[] = 'Therapist';
        }

        if (in_array('ROLE_ADMIN', $this->roles)) {
            $jobs[] = 'Admin';
        }

        return $jobs;
    }

    public function getImageFile(): ?File
    {
        return $this->imageFile;
    }

    public function setImageFile(?File $imageFile): static
    {
        $this->imageFile = $imageFile;

        return $this;
    }

    public function getImageName(): ?string
    {
        return $this->imageName;
    }

    public function setImageName(?string $imageName): static
    {
        $this->imageName = $imageName;

        return $this;
    }

    public function getPasswordChanged(): ?\DateTimeInterface
    {
        return $this->passwordChanged;
    }

    public function setPasswordChanged(\DateTimeInterface $passwordChanged): static
    {
        $this->passwordChanged = $passwordChanged;

        return $this;
    }

    public function getPersonalPhone(): ?string
    {
        return $this->personalPhone;
    }

    public function setPersonalPhone(?string $personalPhone): static
    {
        $this->personalPhone = $personalPhone;

        return $this;
    }

    public function getWorkPhone(): ?string
    {
        return $this->workPhone;
    }

    public function setWorkPhone(string $workPhone): static
    {
        $this->workPhone = $workPhone;

        return $this;
    }

    public function getFormattedPhone(): ?string
    {
        $ret = '';
        if ($this->workPhone) {
            $ret = '(' . substr($this->workPhone, 0, 3) . ') ' . substr($this->workPhone, 3, 3) . '-' . substr($this->workPhone, 6);
        }

        return $ret;
    }

    public function getSignature(): ?string
    {
        return $this->signature;
    }

    public function setSignature(?string $signature): static
    {
        $this->signature = $signature;

        return $this;
    }

    public function isActive(): ?bool
    {
        return $this->active;
    }

    public function setActive(bool $active): static
    {
        $this->active = $active;

        return $this;
    }

    public function getLastLogin(): ?\DateTimeInterface
    {
        return $this->lastLogin;
    }

    public function setLastLogin(?\DateTimeInterface $lastLogin): static
    {
        $this->lastLogin = $lastLogin;

        return $this;
    }

    public function generateVCard(): string
    {
        list($fname, $lname) = explode(' ', $this->name, 2);
        $b64image = null;
        $fileExt = null;

        if ($this->imageName) {
            $fullFileName = dirname(dirname(__DIR__))."/public/{$_ENV['USER_IMAGE_PATH']}/{$this->imageName}";
            $fileExt = strtoupper(pathinfo($fullFileName, PATHINFO_EXTENSION));
            
            $b64image = base64_encode(
                file_get_contents($fullFileName)
            );
        }

        return 'BEGIN:VCARD' .
            "\nVERSION:3.0" .
            "\nN:{$lname};{$fname}" .
            "\nFN:$this->name" .
            "\nORG:{$this->company->getName()}" .
            ($this->workPhone ? "\nTEL;TYPE=WORK,VOICE:$this->workPhone" : null) .
            ($this->email ? "\nEMAIL;TYPE=WORK,INTERNET:$this->email" : null) .
            "\nREV:" . date('c') .
            ($this->imageName ? "\nPHOTO;TYPE={$fileExt};ENCODING=b:{$b64image}" : null) .
            "\nEND:VCARD";
    }
}
