<?php

namespace App\Controller\OgRepository\Image;

use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\DeployImageInput;
use App\Dto\Input\RenameImageInput;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

#[AsController]
class RenameAction extends AbstractOgRepositoryController
{
    /**
     * @throws TransportExceptionInterface
     * @throws ServerExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ClientExceptionInterface
     */
    public function __invoke(RenameImageInput $input, ImageImageRepository $imageImageRepository): JsonResponse
    {
        $image = $imageImageRepository->getImage();

        if ($image->isGlobal()) {
            $repositories = $image->getImageImageRepositories();

            if ($repositories->count() === 0) {
                return $this->jsonError('Image is not in any repository');
            }

            if (!$this->isAvailableInAllRepositories($repositories)) {
                $this->logger->info('Image is not available in all repositories', ['image' => $image->getName()]);
                return $this->jsonError('Image is not available in all repositories');
            }

            $repoWithImage = $this->entityManager
                ->getRepository(ImageImageRepository::class)
                ->findBy(['image' => $image, 'repository' => $imageImageRepository->getRepository()]);
        } else {
            $repoWithImage = [$imageImageRepository];
        }

        $hasError = false;

        foreach ($repoWithImage as $repository) {
            $content = $this->renameImageInRepository($repository, $input->newName);

            if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
                $hasError = true;
            }

            $repository->setName($input->newName);
            $this->entityManager->persist($repository);
        }

        $this->entityManager->flush();

        if ($hasError) {
            throw new BadRequestHttpException('An error occurred while renaming the image: ' . $content['error'] . ' - ' . $content['details']);
        }

        return new JsonResponse([], Response::HTTP_OK);
    }

    /**
     * @throws RedirectionExceptionInterface
     * @throws ClientExceptionInterface
     * @throws ServerExceptionInterface
     */
    private function isAvailableInAllRepositories($repositories): bool
    {
        foreach ($repositories as $repository) {
            try {
                $this->createRequest('GET', 'http://' . $repository->getRepository()->getIp() . ':8006/ogrepository/v1/status');
            } catch (TransportExceptionInterface $e) {
                return false;
            }
        }
        return true;
    }

    /**
     * @throws TransportExceptionInterface
     * @throws ServerExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ClientExceptionInterface
     */
    private function renameImageInRepository(ImageImageRepository $repository, string $newName): array
    {
        $params = [
            'json' => [
                'ID_img' => $repository->getImageFullsum(),
                'image_new_name' => $newName,
            ]
        ];

        return $this->createRequest(
            'PUT',
            'http://' . $repository->getRepository()->getIp() . ':8006/ogrepository/v1/images/rename',
            $params
        );

    }

    private function jsonError(string $message): JsonResponse
    {
        return new JsonResponse(
            ['error' => $message, 'code' => Response::HTTP_INTERNAL_SERVER_ERROR],
            Response::HTTP_BAD_REQUEST
        );
    }

}