<?php

namespace App\Controller\OgRepository\Webhook;

use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Entity\Trace;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;

#[AsController]
class ResponseController extends AbstractOgRepositoryController
{
    #[Route('/og-repository/webhook', name: 'og_repository_webhook', methods: ['POST'])]
    public function repositoryWebhook(Request $request): JsonResponse
    {
        $data = json_decode($request->getContent(), true);

        if (!isset($data['job_id'])) {
            return $this->jsonResponseError('Invalid request', Response::HTTP_BAD_REQUEST);
        }

        $action = $data['job_id'];

        return match (true) {
            str_starts_with($action, "CreateAuxiliarFiles_") => $this->handleImageRepositoryAction($data, true),
            str_starts_with($action, "TransferImage_"), str_starts_with($action, "ExportImage_") => $this->processImageAction($data),
            str_starts_with($action, "BackupImage_") => $this->handleImageRepositoryAction($data),
            str_starts_with($action, "ConvertImageToVirtual") => $this->handleImageRepositoryAction($data),
            str_starts_with($action, "ConvertImageFromVirtual") => $this->handleImageRepositoryAction($data),
            default => $this->jsonResponseError('Invalid action', Response::HTTP_BAD_REQUEST),
        };
    }

    private function handleImageRepositoryAction(array $data, bool $setFullsum = false): JsonResponse
    {
        $trace = $this->getTrace($data['job_id']);
        if (!$trace) return $this->jsonResponseError('Trace not found');

        $imageImageRepository = $this->getImageImageRepository($trace);
        if (!$imageImageRepository) return $this->jsonResponseError('Image not found', Response::HTTP_NOT_FOUND, $trace);

        $imageImageRepository->setStatus(ImageStatus::SUCCESS);
        $this->entityManager->persist($imageImageRepository);

        if (isset($data['success']) && $data['success'] !== true) {
            $this->updateTraceStatus($trace, TraceStatus::FAILED, $data['output'] ?? 'Action failed');
            return new JsonResponse(['message' => 'Success'], Response::HTTP_OK);
        }

        if ($setFullsum) {
            $imageImageRepository->setImageFullsum($data['image_id']);
        }

        $this->entityManager->persist($imageImageRepository);
        $this->updateTraceStatus($trace, TraceStatus::SUCCESS);

        return new JsonResponse(['message' => 'Success'], Response::HTTP_OK);
    }

    private function processImageAction(array $data): JsonResponse
    {
        $trace = $this->getTrace($data['job_id']);
        if (!$trace) return $this->jsonResponseError('Trace not found');

        $image = $this->getImage($trace);
        $repository = $this->getRepository($trace);
        $originImageImageRepository = $this->getImageImageRepository($trace);
        if (!$image) return $this->jsonResponseError('Image not found', Response::HTTP_NOT_FOUND, $trace);
        if (!$repository) return $this->jsonResponseError('Repository not found', Response::HTTP_NOT_FOUND, $trace);
        if (!$originImageImageRepository) return $this->jsonResponseError('ImageImageRepository not found', Response::HTTP_NOT_FOUND, $trace);

        $originImageImageRepository->setStatus(ImageStatus::SUCCESS);
        $this->entityManager->persist($originImageImageRepository);
        $this->entityManager->flush();

        if ($data['success'] !== true) {
            return $this->jsonResponseError('Action failed', Response::HTTP_BAD_REQUEST, $trace);
        }

        $latestImageRepo = $this->entityManager->getRepository(ImageImageRepository::class)->findLatestVersionByImageAndRepository($image, $repository);

        $newImageRepo = new ImageImageRepository();
        $newImageRepo->setName($originImageImageRepository->getName());
        $newImageRepo->setImage($image);
        $newImageRepo->setVersion($originImageImageRepository->getVersion());
        $newImageRepo->setRepository($repository);
        $newImageRepo->setPartitionInfo($originImageImageRepository->getPartitionInfo());
        $newImageRepo->setStatus(ImageStatus::SUCCESS);

        if ($trace->getInput()['imageImageRepositoryUuid'] ?? false) {
            $existingRepo = $this->entityManager->getRepository(ImageImageRepository::class)
                ->findOneBy(['uuid' => $trace->getInput()['imageImageRepositoryUuid']]);

            if ($existingRepo) {
                $newImageRepo->setImageFullsum($existingRepo->getImageFullsum());
            }
        }

        $this->entityManager->persist($newImageRepo);
        $this->updateTraceStatus($trace, TraceStatus::SUCCESS);

        return new JsonResponse(['message' => 'Success'], Response::HTTP_OK);
    }

    private function updateTraceStatus(Trace $trace, string $status, string $output = null): void
    {
        $trace->setStatus($status);
        $trace->setFinishedAt(new \DateTime());

        if ($output !== null) {
            $trace->setOutput($output);
        }

        $this->entityManager->persist($trace);
        $this->entityManager->flush();
    }

    private function getTrace(string $jobId): ?Trace
    {
        return $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $jobId]);
    }

    private function getImage(Trace $trace): ?Image
    {
        return $this->entityManager->getRepository(Image::class)
            ->findOneBy(['uuid' => $trace->getInput()['imageUuid']]);
    }

    private function getRepository(Trace $trace): ?ImageRepository
    {
        return $this->entityManager->getRepository(ImageRepository::class)
            ->findOneBy(['uuid' => $trace->getInput()['repositoryUuid']]);
    }

    private function getImageImageRepository(Trace $trace): ?ImageImageRepository
    {
        return $this->entityManager->getRepository(ImageImageRepository::class)
            ->findOneBy(['uuid' => $trace->getInput()['imageImageRepositoryUuid']]);
    }

    private function jsonResponseError(string $message, int $status = Response::HTTP_BAD_REQUEST, ?Trace $trace = null): JsonResponse
    {
        if ($trace) {
            $this->updateTraceStatus($trace, TraceStatus::FAILED, $message);
        }
        return new JsonResponse(['message' => $message], $status);
    }
}
