<?php

namespace App\Controller\OgDhcp\Subnet;

use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Entity\Client;
use App\Entity\Subnet;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
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 SyncAction extends AbstractOgDhcpController
{
    /**
     * @throws TransportExceptionInterface
     * @throws ServerExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ClientExceptionInterface
     */
    public function __invoke(EntityManagerInterface $entityManager): JsonResponse
    {
        $content = $this->createRequest('GET', 'http://'.$this->ogDhcpApiUrl . '/ogdhcp/v1/subnets');

        $arraySync = [];

        foreach ($content['message'] as $subnet) {
            $subnetEntity = $this->entityManager->getRepository(Subnet::class)->findOneBy(['serverId' => $subnet['id']]);
            if ($subnetEntity) {
                $this->extracted($subnetEntity, $subnet);
                $this->entityManager->persist($subnetEntity);
            } else {
                $subnetEntity = new Subnet();
                $this->extracted($subnetEntity, $subnet);
            }

            $arraySync[] = $subnet['id'];

            $subnetEntity->setServerId($subnet['id']);
            $subnetEntity->setSynchronized(true);
            $this->entityManager->persist($subnetEntity);
        }

        $this->setSynchronized($arraySync);

        $this->entityManager->flush();

        return new JsonResponse(data: $content, status: Response::HTTP_OK);
    }

    /**
     * @param Subnet|null $subnetEntity
     * @param mixed $subnet
     * @return void
     */
    private function extracted(Subnet|null $subnetEntity, mixed $subnet): void
    {
        $getParsedData = $this->getIpAddressAndNetmaskFromCIDRService->__invoke($subnet['subnet']);

        $subnetEntity->setName('Subred -'.$subnet['id']);
        $subnetEntity->setBootFileName($subnet['boot-file-name'] ?? null);
        $subnetEntity->setIpAddress($getParsedData['ip']);
        $subnetEntity->setNetmask($getParsedData['mask']);
        $subnetEntity->setNextServer($subnet['next-server'] ?? null);

        foreach ($subnet['reservations'] as $host) {
            $hostEntity = $this->entityManager->getRepository(Client::class)->findOneBy(['mac' => $host['hw-address']]);
            if ($hostEntity){
                $subnetEntity->addClient($hostEntity);
            }
        }
    }

    public function setSynchronized(array $array): void
    {
        $this->entityManager->createQueryBuilder()
            ->update(Subnet::class, 's')
            ->set('s.synchronized', 'false')
            ->where('s.serverId NOT IN (:array)')
            ->setParameter('array', array_values($array))
            ->getQuery()
            ->getResult();
    }
}