<?php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use App\Config\ConnectorProvider;
use App\Repository\ConnectorRepository;
use App\State\ConnectorCreateProcessor;
use App\State\ConnectorDeleteProcessor;
use App\State\MyConnectorsProvider;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Uid\Uuid;

#[ApiResource(
    shortName: 'Connector',
    operations: [
        new GetCollection(
            openapiContext: [
                'summary' => 'Retrieve all my Connectors',
                'description' => 'This endpoint allows you to retrieve all connectors linked to your account. These connectors can be linked to Watchlists to automate domain name purchases as soon as they are detected as deleted.',
            ],
            normalizationContext: ['groups' => 'connector:list'],
            provider: MyConnectorsProvider::class,
        ),
        new Get(
            openapiContext: [
                'summary' => 'Retrieve one of my connectors',
                'description' => 'This endpoint allows you to retrieve the details of one of the Connectors.',
            ],
            normalizationContext: ['groups' => 'connector:list'],
            security: 'object.getUser() == user'
        ),
        new Post(
            openapiContext: [
                'summary' => 'Create a Connector',
                'description' => 'This endpoint allows you to create a cConnector from the information you provide in the request payload.',
            ],
            normalizationContext: ['groups' => ['connector:create', 'connector:list']],
            denormalizationContext: ['groups' => 'connector:create'],
            processor: ConnectorCreateProcessor::class
        ),
        new Delete(
            openapiContext: [
                'summary' => 'Delete a Connector',
                'description' => 'This endpoint allows you to delete a Connector. If the Connector is linked to Watchlists, they will not be deleted but will no longer be linked to a Connector.',
            ],
            security: 'object.getUser() == user',
            processor: ConnectorDeleteProcessor::class
        ),
    ]
)]
#[ORM\Entity(repositoryClass: ConnectorRepository::class)]
class Connector
{
    #[ORM\Id]
    #[ORM\Column(type: 'uuid')]
    #[Groups(['connector:list', 'watchlist:list'])]
    private ?string $id;

    #[ORM\ManyToOne(inversedBy: 'connectors')]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    public ?User $user = null;

    #[Groups(['connector:list', 'connector:create', 'watchlist:list'])]
    #[ORM\Column(enumType: ConnectorProvider::class)]
    private ?ConnectorProvider $provider = null;

    #[Groups(['connector:create'])]
    #[ORM\Column]
    private array $authData = [];

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

    #[Groups(['connector:list', 'watchlist:list'])]
    #[ORM\Column]
    private ?\DateTimeImmutable $createdAt = null;

    #[Groups(['connector:list'])]
    protected int $watchlistCount;

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

    public function __construct()
    {
        $this->id = Uuid::v4();
        $this->watchlists = new ArrayCollection();
        $this->domainPurchases = new ArrayCollection();
    }

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

    public function getUser(): ?User
    {
        return $this->user;
    }

    public function setUser(?User $user): static
    {
        $this->user = $user;

        return $this;
    }

    public function getAuthData(): array
    {
        return $this->authData;
    }

    public function setAuthData(array $authData): static
    {
        $this->authData = $authData;

        return $this;
    }

    public function getProvider(): ?ConnectorProvider
    {
        return $this->provider;
    }

    public function setProvider(ConnectorProvider $provider): static
    {
        $this->provider = $provider;

        return $this;
    }

    /**
     * @return Collection<int, Watchlist>
     */
    public function getWatchlists(): Collection
    {
        return $this->watchlists;
    }

    public function addWatchlist(Watchlist $watchlist): static
    {
        if (!$this->watchlists->contains($watchlist)) {
            $this->watchlists->add($watchlist);
            $watchlist->setConnector($this);
        }

        return $this;
    }

    public function removeWatchlist(Watchlist $watchlist): static
    {
        if ($this->watchlists->removeElement($watchlist)) {
            // set the owning side to null (unless already changed)
            if ($watchlist->getConnector() === $this) {
                $watchlist->setConnector(null);
            }
        }

        return $this;
    }

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

    public function setCreatedAt(\DateTimeImmutable $createdAt): static
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    public function getWatchlistCount(): ?int
    {
        return $this->watchlists->count();
    }

    /**
     * @return Collection<int, DomainPurchase>
     */
    public function getDomainPurchases(): Collection
    {
        return $this->domainPurchases;
    }

    public function addDomainPurchase(DomainPurchase $domainPurchase): static
    {
        if (!$this->domainPurchases->contains($domainPurchase)) {
            $this->domainPurchases->add($domainPurchase);
            $domainPurchase->setConnector($this);
        }

        return $this;
    }

    public function removeDomainPurchase(DomainPurchase $domainPurchase): static
    {
        if ($this->domainPurchases->removeElement($domainPurchase)) {
            // set the owning side to null (unless already changed)
            if ($domainPurchase->getConnector() === $this) {
                $domainPurchase->setConnector(null);
            }
        }

        return $this;
    }
}
