<?php

namespace App\State\Processor;

use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\Validator\ValidatorInterface;
use App\Controller\OgAgent\CreateImageAction;
use App\Dto\Input\ImageInput;
use App\Repository\ImageRepository;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;

readonly class ImageProcessor implements ProcessorInterface
{
    public function __construct(
        private ImageRepository                     $imageRepository,
        private ValidatorInterface                  $validator,
        private CreateImageAction                   $createImageActionController,
        private KernelInterface                     $kernel,
        private LoggerInterface                     $logger,
    )
    {
    }

    /**
     * @throws \Exception
     * @throws TransportExceptionInterface
     */
    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
    {
        switch ($operation){
            case $operation instanceof Post:
            case $operation instanceof Put:
            case $operation instanceof Patch:
                return $this->processCreateOrUpdate($data, $operation, $uriVariables, $context);
            case $operation instanceof Delete:
                return $this->processDelete($data, $operation, $uriVariables, $context);
        }
    }

    /**
     * @throws \Exception
     * @throws TransportExceptionInterface
     */
    private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): JsonResponse
    {
        if (!($data instanceof ImageInput)) {
            throw new \Exception(sprintf('data is not instance of %s', ImageInput::class));
        }

        $entity = null;
        if (isset($uriVariables['uuid'])) {
            $entity = $this->imageRepository->findOneByUuid($uriVariables['uuid']);
        }

        try {
            $response = null;
            $image = null;
            if ($data->selectedImage) {
                $response = $this->createImageActionController->__invoke($data->queue, $data->selectedImage->getEntity(), $data->partition->getEntity(), $data->client->getEntity(), $data->gitRepository);   
            } else {

                $image = $data->createOrUpdateEntity($entity);

                if ($data->type === 'monolithic') {
                    $this->validator->validate($image);
                } 

                if ($this->kernel->getEnvironment() !== 'test') {
                    $response = $this->createImageActionController->__invoke($data->queue, $image, null, null, $data->gitRepository);
                }

                if ($data->type === 'monolithic') {
                    $this->imageRepository->save($image);
                }
            }

            if ($response instanceof JsonResponse && $response->getStatusCode() >= 400) {
                $content = json_decode($response->getContent(), true);
                throw new \Exception($content['error'] ?? 'Error creating image');
            }

            if ($response instanceof JsonResponse && $response->getStatusCode() === 200) {
                $jobContent = json_decode($response->getContent(), true, 512, JSON_UNESCAPED_SLASHES);
                $jsonString = json_encode($jobContent, JSON_UNESCAPED_SLASHES);
                return new JsonResponse($jsonString, Response::HTTP_OK, [], true);
            }

            return new JsonResponse(data: ['/clients/' . $image?->getClient()?->getUuid() => ['headers' => []]], status: Response::HTTP_OK);
        } catch (\Exception $e) {
            $this->logger->error('Error processing image creation/update', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            
            throw new \Exception('Error processing image: ' . $e->getMessage());
        }
    }

    private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
    {
        $user = $this->imageRepository->findOneByUuid($uriVariables['uuid']);
        $this->imageRepository->delete($user);

        return null;
    }
}
