<?php

namespace App\Controller\OgBoot\OgLive\Webhook;

use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
use App\Entity\Trace;
use App\Model\OgLiveStatus;
use App\Model\TraceStatus;
use App\Service\Utils\ExtractOgLiveFilenameDateService;
use App\Service\Utils\SimplifyOgLiveFilenameService;
use App\Service\Utils\SymflipyOgLiveFilenameService;
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\Component\Validator\Exception\ValidatorException;
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 InstallOgLiveResponseAction extends AbstractController
{
    public CONST string OG_LIVE_INSTALL_SUCCESS = 'success';
    public CONST string OG_LIVE_INSTALL_FAILED = 'failure';
    const string OG_BOOT_DIRECTORY = '/opt/opengnsys/ogboot/tftpboot/';

    public function __construct(
        protected readonly EntityManagerInterface           $entityManager,
        protected readonly LoggerInterface                  $logger,
        protected readonly SimplifyOgLiveFilenameService    $simplifyOgLiveFilenameService,
        protected readonly ExtractOgLiveFilenameDateService $extractOgLiveFilenameDateService,
    )
    {
    }

    /**
     * @throws \Exception
     */
    #[Route('/og-lives/install/webhook', name: 'install_webhook', methods: ['POST'])]
    public function installWebhook(Request $request): JsonResponse
    {
        $data = json_decode($request->getContent(), true);

        if (!is_array($data)) {
            return new JsonResponse(['error' => 'Invalid JSON data'], Response::HTTP_BAD_REQUEST);
        }

        $this->logger->info('OgLive Webhook data received: '.json_encode($data));

        $data = $data['webhookData'];

        if ($data === null || !isset($data['message'], $data['ogCoreId'], $data['status'])) {
            return new JsonResponse(['error' => 'Invalid or incomplete JSON data'], Response::HTTP_BAD_REQUEST);
        }

        $message = $data['message'];
        $ogCoreId = $data['ogCoreId'];
        $status = $data['status'];

        $ogLive = $this->entityManager->getRepository(OgLive::class)->findOneBy(['uuid' => $ogCoreId]);
        $trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => 'InstallOgLive_'.$ogCoreId]);

        if (!$ogLive) {
            return new JsonResponse(['error' => 'OgLive not found'], Response::HTTP_NOT_FOUND);
        }

        if ($trace) {
            $trace->setStatus($status === self::OG_LIVE_INSTALL_SUCCESS ? TraceStatus::SUCCESS : TraceStatus::FAILED);
            $this->entityManager->persist($trace);
            $this->entityManager->flush();
        }

        if ($ogLive->getStatus() === OgLiveStatus::ACTIVE) {
            return new JsonResponse(['error' => 'OgLive is already active'], Response::HTTP_BAD_REQUEST);
        }

        $this->updateOgLive($ogLive, $message, $status);
        $this->logger->info(sprintf('OgLive %s updated successfully', $ogLive->getChecksum()));

        return new JsonResponse(data: sprintf('OgLive %s updated successfully', $ogLive->getChecksum()), status: Response::HTTP_OK);
    }

    /**
     * @throws \Exception
     */
    private function updateOgLive (OgLive $ogLive, mixed $details, string $status): void
    {
        if ( is_array($details) && $status === self::OG_LIVE_INSTALL_SUCCESS) {
            $ogLive->setName($this->simplifyOgLiveFilenameService->__invoke(str_replace(self::OG_BOOT_DIRECTORY, '', $details['directory'])));
            $ogLive->setDate(new \DateTime($this->extractOgLiveFilenameDateService->__invoke($details['directory'])));
            $ogLive->setFilename(str_replace(self::OG_BOOT_DIRECTORY, '', $details['directory']));
            $ogLive->setInstalled(true);
            $ogLive->setSynchronized(true);
            $ogLive->setChecksum($details['id']);
            $ogLive->setDistribution($details['distribution']);
            $ogLive->setKernel($details['kernel']);
            $ogLive->setArchitecture($details['architecture']);
            $ogLive->setRevision($details['revision']);
            $ogLive->setDirectory($details['directory']);

            $oldDefaultOgLive = $this->entityManager->getRepository(OgLive::class)->findAll();
            foreach ($oldDefaultOgLive as $oldOgLive) {
                $oldOgLive->setIsDefault(false);
                $this->entityManager->persist($oldOgLive);
            }

            $ogLive->setIsDefault(true);
            $this->entityManager->persist($ogLive);
        }

        $ogLive->setStatus($status === self::OG_LIVE_INSTALL_SUCCESS ? OgLiveStatus::ACTIVE : OgLiveStatus::FAILED);
        $ogLive->setInstalled($status === self::OG_LIVE_INSTALL_SUCCESS);

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