<?php

declare(strict_types=1);

namespace App\Module\Directory\Infrastructure\ApiPlatform\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Module\Directory\Domain\Entity\Address;
use App\Module\Directory\Domain\Entity\Client;
use App\Module\Directory\Domain\Entity\CommercialReport;
use App\Module\Directory\Domain\Entity\Contact;
use App\Module\Directory\Domain\Entity\Prospect;
use App\Module\Directory\Domain\Enum\ProspectStatus;
use App\Module\Directory\Domain\Repository\ProspectRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Converts a Prospect into a Client and reassigns its contacts, addresses and
 * commercial reports to the new client (preserving the commercial history).
 *
 * Idempotent: if already converted, returns it unchanged.
 *
 * @implements ProcessorInterface<Prospect, Prospect>
 */
final readonly class ConvertProspectProcessor implements ProcessorInterface
{
    public function __construct(
        private EntityManagerInterface $entityManager,
        private ProspectRepositoryInterface $prospectRepository,
    ) {}

    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): Prospect
    {
        $id       = $uriVariables['id'] ?? null;
        $prospect = is_numeric($id) ? $this->prospectRepository->findById((int) $id) : null;

        if (!$prospect instanceof Prospect) {
            throw new NotFoundHttpException('Prospect not found.');
        }

        // Idempotent: already converted, return as-is.
        if (null !== $prospect->getConvertedClient()) {
            return $prospect;
        }

        $client = new Client();
        $client->setName((string) $prospect->getCompany());
        $client->setEmail($prospect->getEmail());
        $client->setPhone($prospect->getPhone());
        $client->setWebsite($prospect->getWebsite());

        $this->entityManager->persist($client);

        $this->reassignContacts($prospect, $client);
        $this->reassignAddresses($prospect, $client);
        $this->reassignReports($prospect, $client);

        $prospect->setConvertedClient($client);
        $prospect->setStatus(ProspectStatus::Won);

        $this->entityManager->flush();

        return $prospect;
    }

    private function reassignContacts(Prospect $prospect, Client $client): void
    {
        foreach ($this->entityManager->getRepository(Contact::class)->findBy(['prospect' => $prospect]) as $contact) {
            $contact->setClient($client);
            $contact->setProspect(null);
        }
    }

    private function reassignAddresses(Prospect $prospect, Client $client): void
    {
        foreach ($this->entityManager->getRepository(Address::class)->findBy(['prospect' => $prospect]) as $address) {
            $address->setClient($client);
            $address->setProspect(null);
        }
    }

    private function reassignReports(Prospect $prospect, Client $client): void
    {
        foreach ($this->entityManager->getRepository(CommercialReport::class)->findBy(['prospect' => $prospect]) as $report) {
            $report->setClient($client);
            $report->setProspect(null);
        }
    }
}
