<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\PersonBundle\Entity\Person;

use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\MappedSuperclass]
class AbstractPersonResource implements TrackCreationInterface, TrackUpdateInterface
{
    use TrackCreationTrait;

    use TrackUpdateTrait;

    #[ORM\Embedded(class: CommentEmbeddable::class, columnPrefix: 'comment_')]
    #[Groups(['read', 'docgen:read'])]
    private CommentEmbeddable $comment;

    #[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
    #[Groups(['read', 'docgen:read'])]
    private ?string $freeText = null;

    #[ORM\ManyToOne(targetEntity: PersonResourceKind::class, inversedBy: 'personResources')]
    #[ORM\JoinColumn(nullable: true)]
    #[Groups(['read', 'docgen:read'])]
    private ?PersonResourceKind $kind = null;

    #[ORM\ManyToOne(targetEntity: Person::class)]
    #[ORM\JoinColumn(nullable: true)]
    #[Groups(['read', 'docgen:read'])]
    private ?Person $person = null;

    #[ORM\ManyToOne(targetEntity: Person::class, inversedBy: 'resources')]
    #[ORM\JoinColumn(nullable: false)]
    #[Groups(['read'])]
    private ?Person $personOwner = null;

    #[ORM\ManyToOne(targetEntity: ThirdParty::class, inversedBy: 'personResources')]
    #[ORM\JoinColumn(nullable: true)]
    #[Groups(['read', 'docgen:read'])]
    private ?ThirdParty $thirdParty = null;

    public function __construct()
    {
        $this->comment = new CommentEmbeddable();
    }

    public function getComment(): CommentEmbeddable
    {
        return $this->comment;
    }

    public function getFreeText(): ?string
    {
        return $this->freeText;
    }

    public function getKind(): ?PersonResourceKind
    {
        return $this->kind;
    }

    public function getPerson(): ?Person
    {
        return $this->person;
    }

    public function getPersonOwner(): ?Person
    {
        return $this->personOwner;
    }

    /**
     * @Groups({"read", "docgen:read"})
     */
    public function getResourceKind(): string
    {
        if ($this->getPerson() instanceof Person) {
            return 'person';
        }

        if ($this->getThirdParty() instanceof ThirdParty) {
            return 'thirdparty';
        }

        if (null !== $this->getFreeText()) {
            return 'freetext';
        }

        return 'none';
    }

    public function getThirdParty(): ?ThirdParty
    {
        return $this->thirdParty;
    }

    public function setComment(?CommentEmbeddable $comment): self
    {
        if (null === $comment) {
            $this->comment->setComment('');

            return $this;
        }

        $this->comment = $comment;

        return $this;
    }

    public function setFreeText(?string $freeText): self
    {
        $this->freeText = $freeText;

        if ('' !== $freeText && null !== $freeText) {
            $this->setPerson(null);
            $this->setThirdParty(null);
        }

        if ('' === $freeText) {
            $this->freeText = null;
        }

        return $this;
    }

    public function setKind(?PersonResourceKind $kind): self
    {
        $this->kind = $kind;

        return $this;
    }

    public function setPerson(?Person $person): self
    {
        $this->person = $person;

        if (null !== $person) {
            $this->setFreeText('');
            $this->setThirdParty(null);
        }

        return $this;
    }

    public function setPersonOwner(?Person $personOwner): self
    {
        $this->personOwner = $personOwner;

        return $this;
    }

    public function setThirdParty(?ThirdParty $thirdParty): self
    {
        $this->thirdParty = $thirdParty;

        if (null !== $thirdParty) {
            $this->setFreeText('');
            $this->setPerson(null);
        }

        return $this;
    }

    /**
     * @Assert\Callback
     */
    public function validate(ExecutionContextInterface $context, mixed $payload): void
    {
        if (null === $this->person && null === $this->thirdParty && (null === $this->freeText || '' === $this->freeText)) {
            $context->buildViolation('You must associate at least one entity')
                ->addViolation();
        }

        if (null !== $this->person && $this->person === $this->personOwner) {
            $context->buildViolation('You cannot associate a resource with the same person')
                ->addViolation();
        }
    }
}
