<?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\MainBundle\Entity;

use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Serializer\Annotation as Serializer;

/**
 * Contains the single execution of an export.
 *
 * Attached to a stored object, which will contains the result of the execution. The status of the stored object
 * is the status of the export generation.
 *
 * Generated exports should be deleted after a certain time, given by the column `deletedAt`. The stored object can be
 * deleted after the export generation removal.
 */
#[ORM\Entity()]
#[ORM\Table('chill_main_export_generation')]
#[Serializer\DiscriminatorMap('type', ['export_generation' => ExportGeneration::class])]
class ExportGeneration implements TrackCreationInterface
{
    use TrackCreationTrait;

    #[ORM\Id]
    #[ORM\Column(type: 'uuid', unique: true)]
    #[Serializer\Groups(['read'])]
    private UuidInterface $id;


    #[ORM\ManyToOne(targetEntity: StoredObject::class, cascade: ['persist', 'refresh'])]
    #[ORM\JoinColumn(nullable: false)]
    #[Serializer\Groups(['read'])]
    private StoredObject $storedObject;

    public function __construct(
        #[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: false, options: ['default' => ''])]
        #[Serializer\Groups(['read'])]
        private string $exportAlias,
        #[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, nullable: false, options: ['default' => '[]'])]
        private array $options = [],
        #[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: true)]
        private ?\DateTimeImmutable $deleteAt = null,

        /**
         *  The related saved export.
         *
         * Note that, in some case, the options of this ExportGeneration are not equals to the options of the saved export.
         * This happens when the options of the saved export are updated.
         */
        #[ORM\ManyToOne(targetEntity: SavedExport::class)]
        #[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
        private ?SavedExport $savedExport = null,
    ) {
        $this->id = Uuid::uuid4();
        $this->storedObject = new StoredObject(StoredObject::STATUS_PENDING);
    }

    public function setDeleteAt(?\DateTimeImmutable $deleteAt): ExportGeneration
    {
        $this->deleteAt = $deleteAt;

        return $this;
    }

    public function getDeleteAt(): ?\DateTimeImmutable
    {
        return $this->deleteAt;
    }

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

    public function getStoredObject(): StoredObject
    {
        return $this->storedObject;
    }

    public function getExportAlias(): string
    {
        return $this->exportAlias;
    }

    public function getOptions(): array
    {
        return $this->options;
    }

    public function getSavedExport(): ?SavedExport
    {
        return $this->savedExport;
    }

    #[Serializer\Groups(['read'])]
    #[Serializer\SerializedName('status')]
    public function getStatus(): string
    {
        return $this->getStoredObject()->getStatus();
    }

    public function setSavedExport(SavedExport $savedExport): self
    {
        $this->savedExport = $savedExport;

        return $this;
    }

    public function isLinkedToSavedExport(): bool
    {
        return null !== $this->savedExport;
    }

    /**
     * Compares the options of the saved export and the current export generation.
     *
     * Return false if the current export generation's options are not equal to the one in the saved export. This may
     * happens when we update the configuration of a saved export.
     */
    public function isConfigurationDifferentFromSavedExport(): bool
    {
        if (!$this->isLinkedToSavedExport()) {
            return false;
        }

        return $this->savedExport->getOptions() !== $this->getOptions();
    }

    public static function fromSavedExport(SavedExport $savedExport, ?\DateTimeImmutable $deletedAt = null, ?array $overrideOptions = null): self
    {
        $generation = new self($savedExport->getExportAlias(), $overrideOptions ?? $savedExport->getOptions(), $deletedAt, $savedExport);
        $generation->getStoredObject()->setTitle($savedExport->getTitle());

        return $generation;
    }
}
