<?php

namespace App\Controller\OgAgent;

use App\Entity\Client;
use App\Entity\OperativeSystem;
use App\Entity\Partition;
use App\Model\ClientStatus;
use App\Model\OgLiveStatus;
use App\Service\CreatePartitionService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\Internal\ClientState;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
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 StatusAction extends AbstractOgAgentController
{
    /**
     * @throws TransportExceptionInterface
     * @throws ServerExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ClientExceptionInterface
     */
    public function __invoke(Client $client): JsonResponse
    {
        $response = null;

        if (!$client->getIp()) {
            throw new BadRequestHttpException('IP is required');
        }

        if ($client->getStatus() === ClientStatus::OG_LIVE
            || $client->getStatus() === ClientStatus::OFF
            || $client->getStatus() === ClientStatus::BUSY
            || $client->getStatus() === ClientStatus::INITIALIZING) {
            $response = $this->getOgLiveStatus($client);
        }

        if ($client->getStatus() === ClientStatus::LINUX
            || $client->getStatus() === ClientStatus::MACOS
            || $client->getStatus() === ClientStatus::WINDOWS) {
            $response = $this->getSOStatus($client);
        }

        return new JsonResponse(
            data: ['status' => $response],
            status: $response === Response::HTTP_OK ? Response::HTTP_OK : Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    /**
     * @throws TransportExceptionInterface
     * @throws ServerExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ClientExceptionInterface
     */
    public function getOgLiveStatus (Client $client): JsonResponse|int|string
    {
        $this->logger->info('Checking client status', ['client' => $client->getId()]);

        $params = [
            'json' => [
                'full-config' => false
            ]
        ];

        $data = $this->createRequest(
            method: 'POST',
            url: 'https://' . $client->getIp() . ':8000/opengnsys/status',
            params: $params,
            token: $client->getToken(),
        );

        if (isset($data['error']) && $data['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
            $this->logger->error('Error checking client status', ['client' => $client->getId()]);
            $client->setStatus(ClientStatus::OFF);
            $this->entityManager->persist($client);
            $this->entityManager->flush();

            throw new BadRequestHttpException('Error checking client status: ' . $data['error'] . ' (' . $data['details'] . ')');
        }

        if (isset($data['cfg'])) {
            $this->logger->info('Creating partitions', ['data' => $data['cfg']]);
            $this->createPartitionService->__invoke($data, $client);
        }

        $client->setStatus(ClientStatus::OG_LIVE);
        $this->entityManager->persist($client);
        $this->entityManager->flush();

        return Response::HTTP_OK;
    }

    /**
     * @throws TransportExceptionInterface
     * @throws ServerExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ClientExceptionInterface
     */
    public function getSOStatus (Client $client): JsonResponse|int
    {
        $data = $this->createRequest(
            method: 'POST',
            url: 'https://' . $client->getIp() . ':8000/opengnsys/status',
            params: [
                'full-config' => false,
            ],
            token: $client->getToken(),
        );

        if (isset($data['cfg'])) {
            $this->createPartitionService->__invoke($data, $client);
        }

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

        return Response::HTTP_OK;
    }
}