<?php
// src/OgBootBundle/Controller/OgBootController.php

namespace App\OgBootBundle\Controller;
use OpenApi\Annotations as OA;
use Psr\Log\LoggerInterface;
use App\OgBootBundle\Service\CurlRequestService;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use App\OgBootBundle\Message\InstallOgliveMessage;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Component\Process\Process;
use Exception;


class OgBootController
{
    private $logger;
    /**
     * @OA\Info(title="Ogboot API", version="1.0")
     */

    private $curlRequestService;
    private $httpClient;
    private $params;
    private $tftpbootDir;
    public function __construct(CurlRequestService $curlRequestService, LoggerInterface $logger, HttpClientInterface $httpClient, ParameterBagInterface $params, protected readonly string $ogBootIP, protected readonly string $ogBootPort)
    {
        $this->curlRequestService = $curlRequestService;
        $this->logger = $logger;
        $this->httpClient = $httpClient;
	    $this->params = $params; // Accedemos a las variables de entorno a través de ParameterBagInterface
	    $this->tftpbootDir = $params->get('tftpboot_dir');
    }

/*Tabla de Contenido
Obtener configuración de ogboot - GET /ogboot/config x
Obtener datos de rendimiento - GET /ogboot/status x
Mostrar información de todos los clientes ogLive instalados - GET /ogboot/oglives x 
Mostrar información de un cliente ogLive instalado - GET /ogboot/oglives/{Index|Dir} x
Mostrar información del cliente ogLive predeterminado - GET /ogboot/oglives/default x
Cambiar ogLive predeterminado - POST /ogboot/oglives/default/{Index} x 
Instalar nuevo cliente ogLive desde imagen descargada - POST /ogboot/oglive/{Index/iso} ----
Desinstalar cliente ogLive y eliminar imagen - DELETE /ogboot/oglives/{Index/iso} -------
Regenerar archivo de información de los ogLive - PUT /ogboot/oglives
Mostrar menú de descarga de imagen de ogLive - GET /ogboot/images/download X 

/////////////////////////////////////////////

Obtener todos los archivos de arranque - GET /ogboot/pxes
Obtener archivo de arranque - GET /ogboot/clients/pxes/{mac}
Crear archivo de arranque - POST /ogboot/pxes
Eliminar archivo de arranque - DELETE /ogboot/clients/pxes
Obtener todas las plantillas - GET /ogboot/pxe-templates
Obtener contenido de la plantilla - GET /ogboot/pxe-templates/{nombre}
Crear plantilla - POST /ogboot/pxe-templates
Regenerar plantilla - PUT /ogboot/pxe-templates
*/

/**
 * @Route("/ogboot/v1/status", name="getStatus", methods={"GET"})
 * @OA\Get(
 *     path="/ogboot/v1/status",
 *     summary="Get ogboot status",
 *     @OA\Response(
 *         response=200,
 *         description="Status retrieved successfully",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="disk_usage", type="object",
 *                 @OA\Property(property="total", type="string", example="20G"),
 *                 @OA\Property(property="used", type="string", example="15G"),
 *                 @OA\Property(property="available", type="string", example="5G"),
 *                 @OA\Property(property="percentage", type="string", example="75%")
 *             ),
 *             @OA\Property(property="default_oglive", type="string", example="ogLive-5.11.0-r20210413"),
 *             @OA\Property(
 *                 property="installed_oglives",
 *                 type="array",
 *                 @OA\Items(ref="#/components/schemas/OgLive")
 *             ),
 *             @OA\Property(property="services_status", type="object",
 *                 @OA\Property(property="service_name", type="string", example="nginx"),
 *                 @OA\Property(property="status", type="string", example="running")
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=404,
 *         description="No ogLive clients found or no default ogLive client available",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="NOT_FOUND"),
 *             @OA\Property(property="message", type="string", example="No default or installed ogLives found.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Server error occurred while retrieving the status",
 *         @OA\JsonContent(
 *             oneOf={
 *                 @OA\Schema(
 *                     @OA\Property(property="error", type="string", example="FAILED_TO_RETRIEVE_DISK_USAGE"),
 *                     @OA\Property(property="details", type="string", example="Unknown error")
 *                 ),
 *                 @OA\Schema(
 *                     @OA\Property(property="error", type="string", example="FAILED_TO_RETRIEVE_OGLIVE_CONFIGURATION"),
 *                     @OA\Property(property="details", type="string", example="Unknown error")
 *                 ),
 *                 @OA\Schema(
 *                     @OA\Property(property="error", type="string", example="FAILED_TO_RETRIEVE_SERVICES_STATUS"),
 *                     @OA\Property(property="details", type="string", example="Unknown error")
 *                 )
 *             }
 *         )
 *     )
 * )
 */

public function getStatus(): Response
{
    // Llamar a oglivecli para obtener el uso del disco
    $diskUsageResponse = $this->curlRequestService->callOgLive("disk_usage");
    $diskUsageResult = $diskUsageResponse['output'];
    $diskUsageExitCode = $diskUsageResponse['exitCode'];

    if ($diskUsageExitCode !== 0) {
        return new JsonResponse(
            ['error' => 'FAILED_TO_RETRIEVE_DISK_USAGE', 'details' => $diskUsageResult['error'] ?? 'Unknown error'],
            Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    // Llamar a oglivecli para obtener la configuración de los oglives instalados y el oglive por defecto
    $ogLiveResponse = $this->curlRequestService->callOgLive("list_installed_oglives");
    $ogLiveConfigResult = $ogLiveResponse['output'];
    $ogLiveExitCode = $ogLiveResponse['exitCode'];

    $defaultOglive = "";
    $installedOglives = [];
    $ogLiveError = null;

    if ($ogLiveExitCode !== 0) {
        // Capturar el error, pero continuar la ejecución
        $ogLiveError = [
            'error' => 'FAILED_TO_RETRIEVE_OGLIVE_CONFIGURATION',
            'details' => $ogLiveConfigResult['error'] ?? 'Unknown error'
        ];
        $defaultOglive = "";
        $installedOglives = [];
    } else {
        // Extraer datos si el comando fue exitoso
        $defaultOglive = $ogLiveConfigResult['default_oglive'] ?? "";
        $installedOglives = $ogLiveConfigResult['installed_ogLives'] ?? [];
    }

    // Llamar a oglivecli para obtener el estado de los servicios
    $servicesStatusResponse = $this->curlRequestService->callOgLive("check_services_status");
    $servicesStatusResult = $servicesStatusResponse['output'];
    $servicesStatusExitCode = $servicesStatusResponse['exitCode'];

    if ($servicesStatusExitCode !== 0) {
        return new JsonResponse(
            ['error' => 'FAILED_TO_RETRIEVE_SERVICES_STATUS', 'details' => $servicesStatusResult['error'] ?? 'Unknown error'],
            Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    $response = [
        'success' => 'Status retrieved successfully',
        'message' => [
            'disk_usage' => $diskUsageResult,
            'default_oglive' => $defaultOglive,
            'installed_oglives' => $installedOglives,
            'services_status' => $servicesStatusResult
        ]
    ];    // Formatear la respuesta final con todos los datos

    // Incluir el error de oglive si existe
    if ($ogLiveError !== null) {
        $response['message']['oglive_error'] = $ogLiveError;
    }

    return new JsonResponse($response, Response::HTTP_OK);
}



/**
 * @Route("/ogboot/v1/oglives/isos", name="getDownloadMenu", methods={"GET"})
 * @OA\Get(
 *     path="/ogboot/v1/oglives/isos",
 *     summary="Get ogLive downloads menu",
 *     @OA\Response(
 *         response=200,
 *         description="Isos retrieved successfully",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string"),
 *             @OA\Property(property="message", type="array",
 *                 @OA\Items(ref="#/components/schemas/DownloadOgLive")
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Failed to retrieve isos",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string"),
 *             @OA\Property(property="message", type="string")
 *         )
 *     )
 * )
 */
public function getDownloadMenu(): Response
{
    $operation = 'ogboot.getDownloadMenu';
    $component = 'ogboot';

    // Log de inicio
    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'desc' => 'Attempting to retrieve ISO download menu.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    // Obtener datos
    $downloadsOutput = $this->curlRequestService->callOgLive("download");

    // Error en la llamada
    if (is_array($downloadsOutput) && isset($downloadsOutput['error'])) {
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'params' => ['error' => $downloadsOutput['error']],
            'http_code' => Response::HTTP_INTERNAL_SERVER_ERROR,
            'desc' => 'Failed to retrieve ISOs.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'FAILED_TO_RETRIEVE_ISOS', 'message' => $downloadsOutput['message']],
            Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    // Log de salida exitosa
    $this->logger->info(json_encode([
        'severity' => 'INFO',
        'operation' => $operation,
        'component' => $component,
        'params' => [],
        'http_code' => Response::HTTP_OK,
        'desc' => 'ISOs retrieved successfully.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    // Respuesta
    return new JsonResponse([
        'success' => 'ISOs retrieved successfully',
        'message' => $downloadsOutput['output']['downloads'] ?? []
    ], Response::HTTP_OK);
}


/**
 * @Route("/ogboot/v1/oglives", name="getOglives", methods={"GET"})
 * @OA\Get(
 *     path="/ogboot/v1/oglives",
 *     summary="Get list of all installed ogLive clients",
 *     @OA\Response(
 *         response=200,
 *         description="List of installed ogLive clients retrieved successfully",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string", example="ogLive clients retrieved successfully"),
 *             @OA\Property(property="message", type="object",
 *                 @OA\Property(property="default_oglive", type="string", description="The default ogLive client"),
 *                 @OA\Property(property="installed_ogLives", type="array",
 *                     @OA\Items(ref="#/components/schemas/OgLive")
 *                 )
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=404,
 *         description="No ogLive clients found",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="NOT_FOUND"),
 *             @OA\Property(property="message", type="string", example="No ogLive clients found.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Server or unknown error occurred",
 *         @OA\JsonContent(
 *             oneOf={
 *                 @OA\Schema(
 *                     @OA\Property(property="error", type="string", example="SERVER_ERROR"),
 *                     @OA\Property(property="message", type="string", example="Failed to retrieve ogLive clients due to server error.")
 *                 ),
 *                 @OA\Schema(
 *                     @OA\Property(property="error", type="string", example="UNKNOWN_ERROR"),
 *                     @OA\Property(property="message", type="string", example="An unknown error occurred.")
 *                 )
 *             }
 *         )
 *     )
 * )
 */

 public function getOglives(): Response
 {
     $operation = 'ogboot.getOglives'; // Nombre de la operación
     $component = 'ogboot';            // Componente responsable
 
     // Log inicial: Inicio del endpoint
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'desc' => 'Fetching list of installed ogLive clients.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     $response = $this->curlRequestService->callOgLive('list_installed_oglives');
     $ogLiveConfigResult = $response['output'];
     $exitCode = $response['exitCode'];
 
     // Log de depuración: Respuesta completa del servicio
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'params' => ['response' => $response],
         'desc' => 'Service response for list_installed_oglives.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     if ($exitCode === 404) {
         $httpCode = (string) Response::HTTP_NOT_FOUND;
         $this->logger->info(json_encode([
             'severity' => 'INFO',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'desc' => 'No ogLive clients found.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse(
             ['error' => 'NOT_FOUND', 'message' => 'No ogLive clients found.'],
             Response::HTTP_NOT_FOUND
         );
     } elseif ($exitCode === 500) {
         $httpCode = (string) Response::HTTP_INTERNAL_SERVER_ERROR;
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'desc' => 'Failed to retrieve ogLive clients due to server error.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse(
             ['error' => 'SERVER_ERROR', 'message' => 'Failed to retrieve ogLive clients due to server error.'],
             Response::HTTP_INTERNAL_SERVER_ERROR
         );
     } elseif ($exitCode !== 0) {
         $httpCode = (string) Response::HTTP_INTERNAL_SERVER_ERROR;
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'desc' => 'Unknown error occurred while retrieving ogLive clients.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse(
             ['error' => 'UNKNOWN_ERROR', 'message' => 'An unknown error occurred.'],
             Response::HTTP_INTERNAL_SERVER_ERROR
         );
     }
 
     if (empty($ogLiveConfigResult) || !isset($ogLiveConfigResult['installed_ogLives'])) {
         $httpCode = (string) Response::HTTP_NOT_FOUND;
         $this->logger->info(json_encode([
             'severity' => 'INFO',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'desc' => 'No installed ogLive clients found in the service response.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse(
             ['error' => 'NOT_FOUND', 'message' => 'No ogLive clients found.'],
             Response::HTTP_NOT_FOUND
         );
     }
 
     $httpCode = (string) Response::HTTP_OK;
     $this->logger->info(json_encode([
         'severity' => 'INFO',
         'operation' => $operation,
         'component' => $component,
         'http_code' => $httpCode,
         'desc' => 'ogLive clients retrieved successfully.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     $response = [
         'success' => 'ogLive clients retrieved successfully',
         'message' => $ogLiveConfigResult // Incluye la estructura completa con default_oglive e installed_ogLives
     ];
 
     return new JsonResponse($response, Response::HTTP_OK);
 }
 
 
 

/**
 * @Route("/ogboot/v1/oglives/default", name="getOgliveDefault", methods={"GET"})
 * @OA\Get(
 *     path="/ogboot/v1/oglives/default",
 *     summary="Get information of the default ogLive client",
 *     @OA\Response(
 *         response=200,
 *         description="Successful operation",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string", example="se ha obtenido el oglive por defecto"),
 *             @OA\Property(property="message", ref="#/components/schemas/OgLive")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Failed to retrieve information of the default ogLive client",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="SERVER_ERROR"),
 *             @OA\Property(property="message", type="string", example="Failed to retrieve default ogLive.")
 *         )
 *     )
 * )
 */
public function getOgliveDefault(Request $request): Response
{
    $operation = 'ogboot.getOgliveDefault'; // Nombre de la operación
    $component = 'ogboot';                  // Componente responsable

    // Log inicial: Inicio del endpoint
    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'desc' => 'Fetching default ogLive configuration.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    // Llamar al servicio que obtiene la configuración por defecto
    $response = $this->curlRequestService->callOgLive('get_default');
    $result = $response['output'];
    $exitCode = $response['exitCode'];

    // Log de depuración: Respuesta completa del servicio
    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['response' => $response],
        'desc' => 'Service response for get_default.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    // Manejo de errores basado en el código de salida
    if ($exitCode !== 0) {
        $httpCode = (string) Response::HTTP_INTERNAL_SERVER_ERROR;
        $errorMessage = $result['error'] ?? 'Failed to retrieve default ogLive.';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'desc' => $errorMessage
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'SERVER_ERROR', 'message' => $errorMessage],
            Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    // Log de éxito: Respuesta válida obtenida
    $httpCode = (string) Response::HTTP_OK;
    $this->logger->info(json_encode([
        'severity' => 'INFO',
        'operation' => $operation,
        'component' => $component,
        'http_code' => $httpCode,
        'desc' => 'Default ogLive configuration retrieved successfully.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    // Devolver la respuesta en el formato solicitado
    return new JsonResponse(
        ['success' => 'se ha obtenido el oglive por defecto', 'message' => $result],
        Response::HTTP_OK
    );
}


/**
 * @Route("/ogboot/v1/oglives/{checksum}", name="getOglive", methods={"GET"})
 * @OA\Get(
 *     path="/ogboot/v1/oglives/{checksum}",
 *     summary="Get information of an installed ogLive client",
 *     @OA\Parameter(
 *         name="checksum",
 *         in="path",
 *         description="Checksum of the installed ogLive client",
 *         required=true,
 *         @OA\Schema(
 *             type="string",
 *             example="9e49a085ba74f97a81bdf9b3d0785094"
 *         )
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="ogLive client retrieved successfully",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string", example="ogLive client retrieved successfully"),
 *             @OA\Property(property="message", ref="#/components/schemas/OgLive")
 *         )
 *     ),
 *     @OA\Response(
 *         response=404,
 *         description="ogLive client not found",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="NOT_FOUND"),
 *             @OA\Property(property="message", type="string", example="ogLive client with checksum 9e49a085ba74f97a81bdf9b3d0785094 not found.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Failed to retrieve ogLive client",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="SERVER_ERROR"),
 *             @OA\Property(property="message", type="string", example="Failed to retrieve ogLive client.")
 *         )
 *     )
 * )
 */
public function getOglive(string $checksum): Response
{
    $operation = 'ogboot.getOglive'; // Nombre de la operación
    $component = 'ogboot';           // Componente responsable

    // Log inicial: Inicio del endpoint con el checksum proporcionado
    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['checksum' => $checksum],
        'desc' => 'Fetching ogLive client.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    // Llamar al servicio ogLive para obtener la información del ogLive correspondiente
    $response = $this->curlRequestService->callOgLive("get_info " . escapeshellarg($checksum));
    $result = $response['output'];
    $exitCode = $response['exitCode'];

    // Log de depuración: Respuesta completa del servicio
    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['response' => $response],
        'desc' => 'Service response for get_info.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    // Manejo de errores basado en el código de salida
    if ($exitCode === 404) {
        $httpCode = (string) Response::HTTP_NOT_FOUND;
        $this->logger->info(json_encode([
            'severity' => 'INFO',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['checksum' => $checksum],
            'desc' => 'ogLive client not found.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'NOT_FOUND', 'message' => "ogLive client with checksum $checksum not found."],
            Response::HTTP_NOT_FOUND
        );
    } elseif ($exitCode !== 0) {
        $httpCode = (string) Response::HTTP_INTERNAL_SERVER_ERROR;
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['checksum' => $checksum],
            'desc' => 'Failed to retrieve ogLive client.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'SERVER_ERROR', 'message' => 'Failed to retrieve ogLive client.'],
            Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    // Log de éxito: Respuesta válida obtenida
    $httpCode = (string) Response::HTTP_OK;
    $this->logger->info(json_encode([
        'severity' => 'INFO',
        'operation' => $operation,
        'component' => $component,
        'http_code' => $httpCode,
        'params' => ['checksum' => $checksum],
        'desc' => 'ogLive client retrieved successfully.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    // Formatear la respuesta de éxito con el ogLive encontrado
    return new JsonResponse(
        ['success' => 'ogLive client retrieved successfully', 'message' => $result],
        Response::HTTP_OK
    );
}



/**
 * @Route("/ogboot/v1/oglives/default", name="setOgliveDefault", methods={"PUT"})
 * @OA\Put(
 *     path="/ogboot/v1/oglives/default",
 *     summary="Set default ogLive client",
 *     @OA\RequestBody(
 *         required=true,
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(
 *                 property="checksum",
 *                 type="string",
 *                 example="9e49a085ba74f97a81bdf9b3d0785094",
 *                 description="Checksum of the ogLive client to set as default"
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="ogLive client set as default successfully",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string", example="ogLive client set as default successfully"),
 *             @OA\Property(property="message", ref="#/components/schemas/OgLive")
 *         )
 *     ),
 *     @OA\Response(
 *         response=400,
 *         description="Invalid input data",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="INVALID_INPUT"),
 *             @OA\Property(property="message", type="string", example="Invalid input data: checksum is required.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Failed to set default ogLive client",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="SERVER_ERROR"),
 *             @OA\Property(property="message", type="string", example="Failed to set ogLive as default.")
 *         )
 *     )
 * )
 */
public function setOgliveDefault(Request $request): Response
{
    $operation = 'ogboot.setOgliveDefault';
    $component = 'ogboot';

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'desc' => 'Setting ogLive client as default.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $data = json_decode($request->getContent(), true);

    if (!isset($data['checksum'])) {
        $httpCode = (string) Response::HTTP_BAD_REQUEST;
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'desc' => 'Invalid input data: checksum is required.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'INVALID_INPUT', 'message' => 'Invalid input data: checksum is required.'],
            Response::HTTP_BAD_REQUEST
        );
    }

    $checksum = $data['checksum'];

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['checksum' => $checksum],
        'desc' => 'Checksum received for setting default.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $response = $this->curlRequestService->callOgLive("set_default " . escapeshellarg($checksum));
    $result = $response['output'];
    $exitCode = $response['exitCode'];

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['response' => $response],
        'desc' => 'Service response for set_default.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    if ($exitCode !== 0) {
        $httpCode = (string) Response::HTTP_INTERNAL_SERVER_ERROR;
        $errorMessage = $result['error'] ?? 'Failed to set ogLive as default.';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['checksum' => $checksum],
            'desc' => $errorMessage
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'SERVER_ERROR', 'message' => $errorMessage],
            Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    $httpCode = (string) Response::HTTP_OK;
    $this->logger->info(json_encode([
        'severity' => 'INFO',
        'operation' => $operation,
        'component' => $component,
        'http_code' => $httpCode,
        'params' => ['checksum' => $checksum],
        'desc' => 'ogLive client set as default successfully.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    return new JsonResponse(
        ['success' => 'ogLive client set as default successfully', 'message' => $result],
        Response::HTTP_OK
    );
}



/**
 * @Route("/ogboot/v1/oglives/install", name="installOglive", methods={"POST"})
 * @OA\Post(
 *     path="/ogboot/v1/oglives/install",
 *     summary="Install an ogLive client",
 *     @OA\RequestBody(
 *         required=true,
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(
 *                 property="url",
 *                 type="string",
 *                 example="https://ognproject.evlt.uma.es/trac/downloads/ogLive-focal-5.11.0-22-generic-amd64-r20210413.992ebb9.iso",
 *                 description="URL of the ogLive ISO to download and install"
 *             ),
 *             @OA\Property(
 *                 property="id",
 *                 type="string",
 *                 example="12345",
 *                 description="Unique transaction ID to track the ogLive installation process"
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="ogLive client installation initiated",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="message", type="string"),
 *             @OA\Property(property="details", type="object")
 *         )
 *     ),
 *     @OA\Response(
 *         response=400,
 *         description="Invalid input data",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string"),
 *             @OA\Property(property="details", type="string")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Failed to initiate ogLive installation",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string"),
 *             @OA\Property(property="details", type="string")
 *         )
 *     )
 * )
 */

 public function installOglive(Request $request): JsonResponse
 {
     $operation = 'ogboot.installOglive';
     $component = 'ogboot';
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'desc' => 'Initiating ogLive client installation process.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     $data = json_decode($request->getContent(), true);
 
     if (!isset($data['url']) || !isset($data['id'])) {
         $httpCode = (string) JsonResponse::HTTP_BAD_REQUEST;
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'desc' => 'Invalid input data. URL or Transaction ID missing.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse(['error' => 'Invalid input data'], JsonResponse::HTTP_BAD_REQUEST);
     }
 
     $isoUrl = $data['url'];
     $transactionId = $data['id'];
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'params' => ['url' => $isoUrl, 'transaction_id' => $transactionId],
         'desc' => 'Received ISO URL and Transaction ID.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     try {
         $consolePath = $this->params->get('kernel.project_dir') . '/bin/console';
         $command = sprintf(
             'php %s oglive:install %s %s > /dev/null 2>&1',
             escapeshellarg($consolePath),
             escapeshellarg($isoUrl),
             escapeshellarg($transactionId)
         );
 
         $this->logger->debug(json_encode([
             'severity' => 'DEBUG',
             'operation' => $operation,
             'component' => $component,
             'params' => ['command' => $command],
             'desc' => 'Command constructed for execution.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         $process = Process::fromShellCommandline($command);
         $process->setTimeout(null);
         $process->disableOutput();
 
         try {
             $process->start();
 
             $httpCode = (string) JsonResponse::HTTP_ACCEPTED;
             $this->logger->info(json_encode([
                 'severity' => 'INFO',
                 'operation' => $operation,
                 'component' => $component,
                 'http_code' => $httpCode,
                 'params' => ['transaction_id' => $transactionId],
                 'desc' => 'ogLive client installation process started successfully.'
             ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
             return new JsonResponse([
                 'success' => 'ogLive client installation started',
                 'transaction_id' => $transactionId
             ], JsonResponse::HTTP_ACCEPTED);
 
         } catch (\Exception $e) {
             $httpCode = (string) JsonResponse::HTTP_INTERNAL_SERVER_ERROR;
             $this->logger->error(json_encode([
                 'severity' => 'ERROR',
                 'operation' => $operation,
                 'component' => $component,
                 'http_code' => $httpCode,
                 'desc' => 'Error starting ogLive client installation process.',
                 'params' => ['message' => $e->getMessage()]
             ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
             throw $e;
         }
     } catch (\Exception $e) {
         $httpCode = (string) JsonResponse::HTTP_INTERNAL_SERVER_ERROR;
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'desc' => 'Failed to initiate ogLive installation.',
             'params' => ['message' => $e->getMessage()]
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse([
             'error' => 'Failed to initiate ogLive installation',
             'details' => $e->getMessage()
         ], JsonResponse::HTTP_INTERNAL_SERVER_ERROR);
     }
 }
 
 
   
    /**
     * Enviar el resultado al webhook
     * 
     * @param string $webhookUrl
     * @param array $data Datos para enviar al webhook
     */
    private function notifyWebhook(string $webhookUrl, array $data): void
    {
        try {
            error_log('Webhook URL: ' . $webhookUrl);
            $this->logger->info('Webhook URL: ' . $webhookUrl);
	    error_log('Data being sent to webhook: ' . json_encode($data));
	    $this->logger->info('Data being sent to webhook: ' . json_encode($data)); 
            $this->httpClient->request('POST', $webhookUrl, [
                'headers' => [
                    'accept' => 'application/json',
                    'Content-Type' => 'application/json',
                ],
                'body' => json_encode($data),
            ]);
 
        } catch (Exception $e) {
            // Manejo de errores en la notificación del webhook
            error_log('Error sending webhook notification: ' . $e->getMessage());
        }
    }

/**
 * @Route("/ogboot/v1/oglives/{checksum}", name="uninstallOglive", methods={"DELETE"})
 * @OA\Delete(
 *     path="/ogboot/v1/oglives/{checksum}",
 *     summary="Uninstall an ogLive client",
 *     @OA\Parameter(
 *         name="checksum",
 *         in="path",
 *         description="Checksum of the ogLive client to uninstall",
 *         required=true,
 *         @OA\Schema(type="string", example="9e49a085ba74f97a81bdf9b3d0785094")
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="ogLive client uninstalled successfully",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="message", type="string"),
 *             @OA\Property(property="details", type="string")
 *         )
 *     ),
 *     @OA\Response(
 *         response=404,
 *         description="ogLive client not found"
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Failed to uninstall ogLive client",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string")
 *         )
 *     )
 * )
 */
public function uninstallOglive(string $checksum): Response
{
    $operation = 'ogboot.uninstallOglive';
    $component = 'ogboot';

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['checksum' => $checksum],
        'desc' => 'Initiating ogLive client uninstallation.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $response = $this->curlRequestService->callOgLive("uninstall " . escapeshellarg($checksum));
    $result = $response['output'];
    $exitCode = $response['exitCode'];

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['response' => $result, 'exitCode' => $exitCode],
        'desc' => 'Service response for ogLive uninstallation.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    if ($exitCode === 404) {
        $httpCode = '404';
        $this->logger->info(json_encode([
            'severity' => 'INFO',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['checksum' => $checksum],
            'desc' => 'ogLive client not found.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse([
            'error' => 'NOT_FOUND',
            'message' => $result['message'] ?? 'ogLive client not found.'
        ], Response::HTTP_NOT_FOUND);
    }

    if ($exitCode === 403) {
        $httpCode = '403';
        $this->logger->warning(json_encode([
            'severity' => 'WARNING',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['checksum' => $checksum],
            'desc' => 'Attempt to uninstall the default ogLive client.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse([
            'error' => 'FORBIDDEN',
            'message' => $result['message'] ?? 'Cannot uninstall the default ogLive client.'
        ], Response::HTTP_FORBIDDEN);
    }

    if ($exitCode === 500) {
        $httpCode = '500';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['checksum' => $checksum],
            'desc' => 'Server error during ogLive uninstallation.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse([
            'error' => 'SERVER_ERROR',
            'message' => $result['message'] ?? 'Failed to uninstall ogLive client.'
        ], Response::HTTP_INTERNAL_SERVER_ERROR);
    }

    if ($exitCode === 200) {
        $httpCode = '200';
        $this->logger->info(json_encode([
            'severity' => 'INFO',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['checksum' => $checksum],
            'desc' => 'ogLive client uninstalled successfully.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse([
            'message' => $result['message'],
            'details' => $result['details'] ?? ''
        ], Response::HTTP_OK);
    }

    $httpCode = '500';
    $this->logger->error(json_encode([
        'severity' => 'ERROR',
        'operation' => $operation,
        'component' => $component,
        'http_code' => $httpCode,
        'params' => ['checksum' => $checksum],
        'desc' => 'Unknown error during ogLive uninstallation.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    return new JsonResponse([
        'error' => 'UNKNOWN_ERROR',
        'message' => 'An unknown error occurred.'
    ], Response::HTTP_INTERNAL_SERVER_ERROR);
}



/**
 * @Route("/ogboot/v1/pxes", name="get_boot_files", methods={"GET"})
 * @OA\Get(
 *     path="/ogboot/v1/pxes",
 *     summary="Get all PXE boot files",
 *     @OA\Response(
 *         response=200,
 *         description="Successful operation",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(
 *                 property="success",
 *                 type="string",
 *                 example="Boot files retrieved successfully"
 *             ),
 *             @OA\Property(
 *                 property="message",
 *                 type="array",
 *                 @OA\Items(
 *                     type="string",
 *                     description="Boot file"
 *                 )
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Failed to retrieve boot files"
 *     )
 * )
 */
public function getBootFiles(): JsonResponse
{
    $operation = 'ogboot.getBootFiles';
    $component = 'ogboot';

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'desc' => 'Attempting to retrieve boot files.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $directory = $this->tftpbootDir . '/ipxe_scripts';

    if (!is_dir($directory)) {
        $httpCode = '500';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['directory' => $directory],
            'desc' => 'Failed to retrieve boot files: directory not found.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'SERVER_ERROR', 'message' => 'Failed to retrieve boot files: directory not found.'],
            Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    $files = scandir($directory);

    $bootFiles = array_filter($files, function ($file) use ($directory) {
        return !is_dir($directory . '/' . $file) && strpos($file, '01-') === 0;
    });

    if (empty($bootFiles)) {
        $httpCode = '404';
        $this->logger->info(json_encode([
            'severity' => 'INFO',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['directory' => $directory],
            'desc' => 'No boot files found.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'NOT_FOUND', 'message' => 'No boot files found.'],
            Response::HTTP_NOT_FOUND
        );
    }

    $httpCode = '200';
    $this->logger->info(json_encode([
        'severity' => 'INFO',
        'operation' => $operation,
        'component' => $component,
        'http_code' => $httpCode,
        'params' => ['boot_files' => array_values($bootFiles)],
        'desc' => 'Boot files retrieved successfully.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $response = [
        'success' => 'Boot files retrieved successfully',
        'message' => array_values($bootFiles)
    ];

    return new JsonResponse($response, Response::HTTP_OK);
}



/**
 * @Route("/ogboot/v1/pxes/{mac}", name="ogboot_get_boot_file_with_params", methods={"GET"})
 * @OA\Get(
 *     path="/ogboot/v1/pxes/{mac}",
 *     summary="Get boot file with parameters",
 *     @OA\Parameter(
 *         name="mac",
 *         in="path",
 *         description="MAC address",
 *         required=true,
 *         @OA\Schema(type="string", example="00:50:56:22:11:12")
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="Successful operation",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string", example="Boot file retrieved successfully"),
 *             @OA\Property(
 *                 property="message", 
 *                 type="object",
 *                 @OA\Property(property="template_name", type="string", description="Template name (required)", example="pxe"),
 *                 @OA\Property(property="mac", type="string", description="MAC address (required)", example="00:50:56:22:11:12"),
 *                 @OA\Property(property="lang", type="string", description="Language (optional)", example="es_ES.UTF-8"),
 *                 @OA\Property(property="ip", type="string", description="IP address (optional)", example="192.168.2.11"),
 *                 @OA\Property(property="server_ip", type="string", description="Server IP address (optional)", example="192.168.2.1"),
 *                 @OA\Property(property="router", type="string", description="Router (optional)", example="192.168.2.1"),
 *                 @OA\Property(property="netmask", type="string", description="Netmask (optional)", example="255.255.255.0"),
 *                 @OA\Property(property="computer_name", type="string", description="Computer name (optional)", example="pc11"),
 *                 @OA\Property(property="netiface", type="string", description="Network interface (optional)", example="eth0"),
 *                 @OA\Property(property="group", type="string", description="Group (optional)", example="Aula_virtual"),
 *                 @OA\Property(property="ogrepo", type="string", description="Repository IP (optional)", example="192.168.2.1"),
 *                 @OA\Property(property="oglive", type="string", description="Live server IP (optional)", example="192.168.2.1"),
 *                 @OA\Property(property="ogcore", type="string", description="Ogcore IP(optional)", example="192.168.2.1"),
 *                 @OA\Property(property="oglog", type="string", description="Log server IP (optional)", example="192.168.2.1"),
 *                 @OA\Property(property="ogshare", type="string", description="Share server IP (optional)", example="192.168.2.1"),
 *                 @OA\Property(property="oglivedir", type="string", description="Live directory (optional)", example="ogLive"),
 *                 @OA\Property(property="ogprof", type="string", description="Is professor (optional)", example="false"),
 *                 @OA\Property(property="hardprofile", type="string", description="Hardware profile (optional)", example=""),
 *                 @OA\Property(property="ogntp", type="string", description="NTP server (optional)", example=""),
 *                 @OA\Property(property="ogdns", type="string", description="DNS server (optional)", example=""),
 *                 @OA\Property(property="ogproxy", type="string", description="Proxy server (optional)", example=""),
 *                 @OA\Property(property="ogunit", type="string", description="Unit directory (optional)", example=""),
 *                 @OA\Property(property="resolution", type="string", description="Screen resolution (optional)", example="788")
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=404,
 *         description="No boot file found for the specified MAC address",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="NOT_FOUND"),
 *             @OA\Property(property="message", type="string", example="No boot file found for the specified MAC address.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Internal server error"
 *     )
 * )
 */


 public function getBootFile(string $mac): Response
 {
     $operation = 'ogboot.getBootFile';
     $component = 'ogboot';
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'params' => ['mac' => $mac],
         'desc' => 'Retrieving boot file for MAC address.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     $directory = $this->tftpbootDir . '/ipxe_scripts';
     $mac = $this->validateAndFormatMac($mac ?? null);
     $fileName = "01-" . $mac;
     $filePath = "$directory/$fileName";
     $realFilePath = realpath($directory) . '/' . $fileName;
 
     if (strpos($realFilePath, realpath($directory)) !== 0) {
         $httpCode = '403';
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['mac' => $mac, 'attemptedPath' => $realFilePath],
             'desc' => 'Unauthorized access attempt outside the boot directory.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse(
             ['error' => 'UNAUTHORIZED_ACCESS', 'message' => 'Attempted unauthorized access outside the boot directory.'],
             Response::HTTP_FORBIDDEN
         );
     }
 
     if (!file_exists($realFilePath)) {
         $httpCode = '404';
         $this->logger->info(json_encode([
             'severity' => 'INFO',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['mac' => $mac],
             'desc' => 'Boot file not found for specified MAC address.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse(
             ['error' => 'NOT_FOUND', 'message' => 'No boot file found for the specified MAC address.'],
             Response::HTTP_NOT_FOUND
         );
     }
 
     $content = file_get_contents($realFilePath);
     if ($content === false) {
         $httpCode = '500';
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['filePath' => $realFilePath],
             'desc' => 'Failed to read the boot file.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse(
             ['error' => 'FAILED_TO_READ_BOOT_FILE', 'message' => 'Error reading the boot file.'],
             Response::HTTP_INTERNAL_SERVER_ERROR
         );
     }
 
     $templateName = 'unknown';
     $oglivedir = '';
     $kernelArgs = '';
 
     if (preg_match('/#Template:\s*(.*)/', $content, $matches)) {
         $templateName = trim($matches[1]);
     }
 
     if (preg_match('/set ISODIR\s+(.*)/', $content, $matches)) {
         $oglivedir = trim($matches[1]);
     }
 
     if (preg_match('/set kernelargs\s+(.*)/', $content, $matches)) {
         $kernelArgs = trim($matches[1]);
     }
 
     if (empty($kernelArgs)) {
         $httpCode = '200';
         $this->logger->info(json_encode([
             'severity' => 'INFO',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['mac' => $mac, 'templateName' => $templateName],
             'desc' => 'Boot file retrieved without kernel parameters.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse(
             [
                 'success' => 'Boot file retrieved successfully',
                 'message' => [
                     'template_name' => $templateName,
                     'mac' => $mac,
                     'message' => 'Boot file without parameters, possibly a disk boot template.'
                 ]
             ],
             Response::HTTP_OK
         );
     }
 
     parse_str(str_replace(' ', '&', $kernelArgs), $params);
 
     $result = [
         'template_name' => $templateName,
         'mac' => $mac,
         'lang' => $params['LANG'] ?? '',
         'ip' => explode(':', $params['ip'])[0] ?? '',
         'server_ip' => explode(':', $params['ip'])[1] ?? '',
         'router' => explode(':', $params['ip'])[2] ?? '',
         'netmask' => explode(':', $params['ip'])[3] ?? '',
         'computer_name' => explode(':', $params['ip'])[4] ?? '',
         'netiface' => explode(':', $params['ip'])[5] ?? '',
         'group' => $params['group'] ?? '',
         'ogrepo' => $params['ogrepo'] ?? '',
         'oglive' => $params['oglive'] ?? '',
         'ogcore' => $params['ogcore'] ?? '',
         'oglog' => $params['oglog'] ?? '',
         'ogshare' => $params['ogshare'] ?? '',
         'oglivedir' => $oglivedir,
         'ogprof' => $params['ogprof'] ?? '',
         'hardprofile' => $params['hardprofile'] ?? '',
         'ogntp' => $params['ogntp'] ?? '',
         'ogdns' => $params['ogdns'] ?? '',
         'ogproxy' => $params['ogproxy'] ?? '',
         'ogunit' => $params['ogunit'] ?? '',
         'resolution' => $params['vga'] ?? '',
     ];
 
     $httpCode = '200';
     $this->logger->info(json_encode([
         'severity' => 'INFO',
         'operation' => $operation,
         'component' => $component,
         'http_code' => $httpCode,
         'params' => ['mac' => $mac, 'templateName' => $templateName],
         'desc' => 'Boot file retrieved successfully.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     return new JsonResponse(
         ['success' => 'Boot file retrieved successfully', 'message' => $result],
         Response::HTTP_OK
     );
 }
 
 
 

 


/**
 * @Route("/ogboot/v1/pxes", methods={"POST"})
 * @OA\Post(
 *     path="/ogboot/v1/pxes",
 *     summary="Crear archivo PXE",
 *     description="Crea un archivo de arranque PXE con la MAC y plantilla proporcionadas.",
 *     @OA\RequestBody(
 *         required=true,
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="mac", type="string", example="00:50:56:22:11:12"),
 *             @OA\Property(property="template_name", type="string", example="mi_plantilla.ipxe"),
 *             @OA\Property(property="server_ip", type="string", example="192.168.2.1"),
 *             @OA\Property(property="server_pxe_port", type="string", example="8082"),
 *             @OA\Property(property="oglivedir", type="string", example="ogLive")
 *         )
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="Plantilla creada exitosamente",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string", example="Plantilla creada con éxito"),
 *             @OA\Property(property="message", type="string")
 *         )
 *     ),
 *     @OA\Response(
 *         response=400,
 *         description="Entrada inválida o datos requeridos faltantes"
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Error interno del servidor al crear el archivo PXE"
 *     )
 * )
 */


public function createBootFile(Request $request): JsonResponse
{
    $operation = 'ogboot.createBootFile';
    $component = 'ogboot';

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'desc' => 'Starting PXE file creation process.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $data = json_decode($request->getContent(), true);
    $templateName = $data['template_name'] ?? null;
    $mac = $this->validateAndFormatMac($data['mac'] ?? null);
    //Si nos pasan el puerto se lo quitamos ya que server_ip siempre tirara por Samba
    $serverIp = $data['server_ip'] ?? null;
    if ($serverIp && strpos($serverIp, ':') !== false) {
        $serverIp = explode(':', $serverIp)[0];
    }
    //Declaramos serverPxePort que lo usaremos para la llamada por http
    $serverPxePort = $data['server_pxe_port'] ?? null;

    $serverIpPort = $serverIp;
    if (!empty($serverPxePort)) {
        $serverIpPort .= ':' . $serverPxePort;
    }

    $ogLiveDir = $data['oglivedir'] ?? 'ogLive';

    // Verificación de los campos obligatorios
    if (!$templateName || !$mac) {
        $httpCode = '400';
        $this->logger->warning(json_encode([
            'severity' => 'WARNING',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'desc' => 'Missing required fields: mac and/or template_name.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
        return new JsonResponse(['error' => 'Missing required fields: mac and template_name'], Response::HTTP_BAD_REQUEST);
    }

    // Validación adicional para asegurarnos de que no hay caracteres inseguros
    if (!preg_match('/^[a-zA-Z0-9._-]+$/', $templateName) || strpos($templateName, '..') !== false) {
        $httpCode = '400';
        $this->logger->warning(json_encode([
            'severity' => 'WARNING',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['template_name' => $templateName],
            'desc' => 'Invalid template name or unauthorized access attempt.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
        return new JsonResponse(
            ['error' => 'INVALID_TEMPLATE_NAME', 'message' => 'Nombre de la plantilla no válido o intento de acceso no autorizado.'],
            Response::HTTP_BAD_REQUEST
        );
    }


    // Parámetros opcionales
    $parameters = [
        'LANG' => $data['lang'] ?? 'es_ES.UTF-8',
        'ip' => $data['ip'] ?? '',
        'server_pxe_port' => $data['server_pxe_port'] ?? '',
        'router' => $data['router'] ?? '',
        'netmask' => $data['netmask'] ?? '',
        'computer_name' => $data['computer_name'] ?? '',
        'netiface' => $data['netiface'] ?? '',
        'group' => $data['group'] ?? '',
        'ogrepo' => isset($data['ogrepo']) ? explode(':', $data['ogrepo'])[0] : '',
        'ogcore' => isset($data['ogcore']) ? explode(':', $data['ogcore'])[0] : '',
        'oglive' => isset($data['oglive']) ? explode(':', $data['oglive'])[0] : $serverIp,
        'oglog' => isset($data['oglog']) ? explode(':', $data['oglog'])[0] : $serverIp,
        'ogshare' => isset($data['ogshare']) ? explode(':', $data['ogshare'])[0] : $serverIp,
        'oglivedir' => $data['oglivedir'] ?? '',
        'ogprof' => $data['ogprof'] ?? 'false',
        'hardprofile' => $data['hardprofile'] ?? '',
        'ogntp' => $data['ogntp'] ?? '',
        'ogdns' => $data['ogdns'] ?? '',
        'ogproxy' => $data['ogproxy'] ?? '',
        'ogunit' => $data['ogunit'] ?? '',
        'resolution' => $data['resolution'] ?? '788'
    ];

    $templateDir = $this->tftpbootDir . '/ipxe_scripts/templates';
    $templatePath = $templateDir . '/' . $templateName;

    // Verificar si la plantilla existe
    if (!file_exists($templatePath)) {
        $httpCode = '404';
        $this->logger->info(json_encode([
            'severity' => 'INFO',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['template_path' => $templatePath],
            'desc' => 'Template not found.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
        return new JsonResponse(['error' => 'TEMPLATE_NOT_FOUND', 'message' => 'No se encontró la plantilla especificada'], Response::HTTP_NOT_FOUND);
    }

    $templateContent = file_get_contents($templatePath);
    if ($templateContent === false) {
        $httpCode = '500';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['template_path' => $templatePath],
            'desc' => 'Failed to read the template.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
        return new JsonResponse(['error' => 'FAILED_TO_READ_TEMPLATE', 'message' => 'Error al leer la plantilla'], Response::HTTP_INTERNAL_SERVER_ERROR);
    }

    // Construcción de los argumentos del kernel
    $kernelArgs = 'ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogtmpfs=15 ' .
	'oglivedir=${ISODIR}' . ' ' .   
        'LANG=' . $parameters['LANG'] . ' ' .
        'ip=' . $parameters['ip'] . ':' . $serverIp . ':' . $parameters['router'] . ':' . $parameters['netmask'] . ':' . $parameters['computer_name'] . ':' . $parameters['netiface'] . ':none ' .
        'group=' . str_replace(' ', '_', trim($parameters['group'])) . ' ' .
        'ogrepo=' . $parameters['ogrepo'] . ' ' .
        'ogcore=' . $parameters['ogcore'] . ' ' .
        'oglive=' . $parameters['oglive'] . ' ' .
        'oglog=' . $parameters['oglog'] . ' ' .
        'ogshare=' . $parameters['ogshare'] . ' ' .
        'ogprof=' . ($parameters['ogprof'] === 'true' ? 'true' : 'false') . ' ' .
        (!empty($parameters['hardprofile']) ? 'hardprofile=' . str_replace(' ', '_', trim($parameters['hardprofile'])) . ' ' : '') .
        (!empty($parameters['ogntp']) ? 'ogntp=' . $parameters['ogntp'] . ' ' : '') .
        (!empty($parameters['ogdns']) ? 'ogdns=' . $parameters['ogdns'] . ' ' : '') .
        (!empty($parameters['ogproxy']) ? 'ogproxy=' . $parameters['ogproxy'] . ' ' : '') .
        (!empty($parameters['ogunit']) ? 'ogunit=' . $parameters['ogunit'] . ' ' : '') .
        (is_numeric($parameters['resolution']) && $parameters['resolution'] <= 999 ? 'vga=' . $parameters['resolution'] :
            (strpos($parameters['resolution'], ':') !== false ? 'video=' . $parameters['resolution'] : ' ' . $parameters['resolution']));


    // Extraer solo el nombre del directorio si contiene una ruta completa PROVISIONAL
    if (strpos($ogLiveDir, '/') !== false) {
        $ogLiveDir = basename($ogLiveDir);
    }
    $pxeContent = str_replace(
        ['__INFOHOST__', '__SERVERIP__', '__OGLIVE__'],
        [$kernelArgs, $serverIpPort, $ogLiveDir],
        $templateContent
    );


    // Insertar el comentario con el nombre de la plantilla después de #!ipxe
    if (strpos($pxeContent, '#!ipxe') === 0) {
        $pxeContent = "#!ipxe\n#Template: $templateName\n" . substr($pxeContent, 6);
    } else {
        $pxeContent = "#!ipxe\n#Template: $templateName\n" . $pxeContent;
    }

    // Nombre del archivo PXE basado en la MAC
    $pxeFileName = '01-' . $mac;

    // Ruta para guardar el archivo PXE
    $pxeFilePath = $this->tftpbootDir . '/ipxe_scripts/' . $pxeFileName;

    // Crear el archivo PXE
    if (file_put_contents($pxeFilePath, $pxeContent) === false) {
        $httpCode = '500';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'desc' => 'Failed to create PXE file.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
        return new JsonResponse(['error' => 'FAILED_TO_CREATE_PXE_FILE', 'message' => 'Error al crear el archivo PXE'], Response::HTTP_INTERNAL_SERVER_ERROR);
    }

    $templateCacheDir = $this->tftpbootDir . '/menu.lst';
    $pxeFileName = '01-' . $mac;
    $pxeFilePath = $templateCacheDir . '/' . $pxeFileName;

    // Generar archivo si la plantilla es oglives cache o menu
    if ($templateName === 'ogliveCache' || $templateName === 'menu') {
        if ($templateName === 'ogliveCache') {
            $templateCachePath = $templateCacheDir . '/templateCache';
        } elseif ($templateName === 'menu') {
            $templateCachePath = $templateCacheDir . '/templateMenu';
        }
        $templateCacheContent = file_get_contents($templateCachePath);
        $grubContent = str_replace(
            ['__INFOHOST__', '__OGLIVE__'],
            [$kernelArgs, basename($ogLiveDir)],
            $templateCacheContent
        );
    }
    // Generar archivo si la plantilla es de tipo disco/partición
    elseif (in_array($templateName, ['firstDisk_firstPartition', 'firstDisk_secondPartition', 'firstDisk_thirdPartition'])) {
        $templateDiskPath = $templateCacheDir . '/templateDisk';
        $templateDiskContent = file_get_contents($templateDiskPath);

        // Determinar DISK, PART y DISKPART en función del templateName
        $map = [
            'firstDisk_firstPartition' => ['disk' => '01', 'part' => '01', 'diskpart' => '(hd0,gpt1)'],
            'firstDisk_secondPartition' => ['disk' => '01', 'part' => '02', 'diskpart' => '(hd0,gpt1)'],
            'firstDisk_thirdPartition' => ['disk' => '01', 'part' => '03', 'diskpart' => '(hd0,gpt1)'],
        ];

        $diskInfo = $map[$templateName];

        // Sustituir variables en plantilla
        $grubContent = str_replace(
            ['__DISK__', '__PART__', '__DISKPART__'],
            [$diskInfo['disk'], $diskInfo['part'], $diskInfo['diskpart']],
            $templateDiskContent
        );
    }
    // En cualquier otro caso, no se hace nada
    else {
        return new JsonResponse(['success' => 'NO_TEMPLATE_ACTION', 'message' => 'No se requiere generar archivo PXE'], Response::HTTP_OK);
    }

    // Escribir el archivo PXE final (común a ambos casos)
    if (file_put_contents($pxeFilePath, $grubContent) === false) {
        $httpCode = '500';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'desc' => 'Failed to create PXE boot file.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
        return new JsonResponse(['error' => 'FAILED_TO_CREATE_PXE_FILE', 'message' => 'Error al crear el archivo de arranque PXE'], Response::HTTP_INTERNAL_SERVER_ERROR);
    }


    $httpCode = '200';
    $this->logger->info(json_encode([
        'severity' => 'INFO',
        'operation' => $operation,
        'component' => $component,
        'http_code' => $httpCode,
        'desc' => 'PXE file created successfully.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    return new JsonResponse([
        'success' => 'PXE file created successfully',
        'message' => $pxeContent
    ], Response::HTTP_OK);

    // Retornar la plantilla creada en el formato solicitado
    return new JsonResponse([
        'success' => 'PXE file created successfully',
        'message' => $pxeContent
    ], Response::HTTP_OK);
}

    
function validateAndFormatMac($mac)
{
    // Convertir a minúsculas para un formato uniforme
    $mac = strtolower($mac);

    // Comprobar si la MAC tiene el formato correcto con dos puntos (ej. fc:aa:14:21:55:b9)
    if (preg_match('/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/', $mac)) {
        return $mac; // MAC ya está en el formato correcto
    }

    // Comprobar si la MAC tiene el formato sin los dos puntos (ej. fcaa142155b9)
    if (preg_match('/^[0-9a-f]{12}$/', $mac)) {
        // Insertar los dos puntos en la MAC y devolverla en el formato correcto
        return strtolower(implode(':', str_split($mac, 2)));
    }

    // Si no cumple con ninguno de los formatos, devolver un error
    return false; // MAC no válida
}





/**
 * @Route("/ogboot/v1/pxes/{mac}", name="ogboot_delete_boot_file", methods={"DELETE"})
 * @OA\Delete(
 *     path="/ogboot/v1/pxes/{mac}",
 *     summary="Delete PXE boot file",
 *     description="Delete a specific PXE boot file using its MAC address.",
 *     @OA\Parameter(
 *         name="mac",
 *         in="path",
 *         description="MAC address of the client whose boot file is to be deleted",
 *         required=true,
 *         @OA\Schema(type="string", example="00:11:22:33:44:55")
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="Boot file deleted successfully",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string", example="Boot file deleted successfully"),
 *             @OA\Property(property="message", type="string", example="The boot file for MAC 00:11:22:33:44:55 has been deleted.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=404,
 *         description="No boot file found for the specified MAC address",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="No boot file found for the specified MAC address.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Failed to delete the boot file",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="Failed to delete the boot file due to server error.")
 *         )
 *     )
 * )
 */
public function deleteBootFile(string $mac): Response
{
    $operation = 'ogboot.deleteBootFile';
    $component = 'ogboot';

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['mac' => $mac],
        'desc' => 'Attempting to delete boot file.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $directory = $this->tftpbootDir . '/ipxe_scripts';
    $mac = $this->validateAndFormatMac($mac ?? null);
    $fileName = "01-" . $mac;
    $filePath = "$directory/$fileName";

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['filePath' => $filePath],
        'desc' => 'Computed file path for boot file.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    if (!file_exists($filePath)) {
        $httpCode = '404';
        $this->logger->info(json_encode([
            'severity' => 'INFO',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => [
                'mac' => $mac,
                'filePath' => $filePath
            ],
            'desc' => 'Boot file not found.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'NOT_FOUND', 'message' => 'No boot file found for the specified MAC address.'],
            Response::HTTP_NOT_FOUND
        );
    }

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['filePath' => $filePath],
        'desc' => 'Boot file exists, proceeding to delete.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    if (!unlink($filePath)) {
        $httpCode = '500';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => [
                'mac' => $mac,
                'filePath' => $filePath
            ],
            'desc' => 'Failed to delete boot file.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'SERVER_ERROR', 'message' => 'Failed to delete the boot file due to server error.'],
            Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    $httpCode = '200';
    $this->logger->info(json_encode([
        'severity' => 'INFO',
        'operation' => $operation,
        'component' => $component,
        'http_code' => $httpCode,
        'params' => [
            'mac' => $mac,
            'filePath' => $filePath
        ],
        'desc' => 'Boot file deleted successfully.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    return new JsonResponse(
        ['success' => 'Boot file deleted successfully', 'message' => "The boot file for MAC $mac has been deleted."],
        Response::HTTP_OK
    );
}


    
/**
 * @Route("/ogboot/v1/pxe-templates", methods={"GET"})
 * @OA\Get(
 *     path="/ogboot/v1/pxe-templates",
 *     summary="Obtener todas las plantillas PXE",
 *     description="Obtiene una lista de todas las plantillas de arranque PXE disponibles.",
 *     @OA\Response(
 *         response=200,
 *         description="Lista de plantillas de arranque PXE",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string", example="Lista de plantillas obtenida con éxito"),
 *             @OA\Property(
 *                 property="message",
 *                 type="array",
 *                 @OA\Items(type="string", example="mi_plantilla.ipxe")
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Error interno del servidor",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="SERVER_ERROR"),
 *             @OA\Property(property="message", type="string", example="Directorio de plantillas no encontrado")
 *         )
 *     )
 * )
 */
public function getAllTemplates(): JsonResponse
{
    $operation = 'ogboot.getAllTemplates';
    $component = 'ogboot';

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'desc' => 'Attempting to retrieve all templates.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $templateDir = $this->tftpbootDir . '/ipxe_scripts/templates';

    if (!is_dir($templateDir)) {
        $httpCode = '500';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['templateDir' => $templateDir],
            'desc' => 'Template directory not found.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new JsonResponse(
            ['error' => 'SERVER_ERROR', 'message' => 'Directorio de plantillas no encontrado'],
            Response::HTTP_INTERNAL_SERVER_ERROR
        );
    }

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['templateDir' => $templateDir],
        'desc' => 'Template directory exists.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $files = scandir($templateDir);

    $templates = array_filter($files, function ($file) use ($templateDir) {
        return !in_array($file, ['.', '..']) && !is_dir($templateDir . '/' . $file);
    });

    $httpCode = '200';
    $this->logger->info(json_encode([
        'severity' => 'INFO',
        'operation' => $operation,
        'component' => $component,
        'http_code' => $httpCode,
        'params' => [
            'templateDir' => $templateDir,
            'templateCount' => count($templates)
        ],
        'desc' => 'Templates retrieved successfully.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['templates' => array_values($templates)],
        'desc' => 'Template list retrieved.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    return new JsonResponse(
        ['success' => 'Lista de plantillas obtenida con éxito', 'message' => array_values($templates)],
        Response::HTTP_OK
    );
}



/**
 * @Route("/ogboot/v1/pxe-templates/{templateName}", name="get_template", methods={"GET"})
 * @OA\Get(
 *     path="/ogboot/v1/pxe-templates/{templateName}",
 *     summary="Obtener contenido de una plantilla PXE",
 *     description="Obtiene el contenido de una plantilla de arranque PXE específica por su nombre.",
 *     @OA\Parameter(
 *         name="templateName",
 *         in="path",
 *         required=true,
 *         description="Nombre de la plantilla PXE",
 *         @OA\Schema(type="string", example="mi_plantilla.ipxe")
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="Contenido de la plantilla de arranque PXE",
 *         @OA\JsonContent(
 *             @OA\Property(property="success", type="string", example="Plantilla obtenida con éxito"),
 *             @OA\Property(property="template_name", type="string", example="mi_plantilla.ipxe"),
 *             @OA\Property(property="template_content", type="string", example="#!ipxe\nset timeout 0\nset timeout-style hidden\n\nset ISODIR ogLive\nset default 0\nset kernelargs INFOHOST\nkernel tftp://SERVERIP/ogLive/ogvmlinuz ${kernelargs}\ninitrd tftp://SERVERIP/ogLive/oginitrd.img\nboot")
 *         )
 *     ),
 *     @OA\Response(
 *         response=404,
 *         description="Plantilla no encontrada",
 *         @OA\JsonContent(
 *             @OA\Property(property="error", type="string", example="TEMPLATE_NOT_FOUND"),
 *             @OA\Property(property="message", type="string", example="No se encontró la plantilla especificada")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Error interno del servidor",
 *         @OA\JsonContent(
 *             @OA\Property(property="error", type="string", example="FAILED_TO_READ_TEMPLATE"),
 *             @OA\Property(property="message", type="string", example="Error al leer la plantilla")
 *         )
 *     )
 * )
 */

 public function getTemplate(string $templateName): Response
 {
     $operation = 'ogboot.getTemplate';
     $component = 'ogboot';
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'params' => ['templateName' => $templateName],
         'desc' => 'Attempting to retrieve template.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     $templateDir = $this->tftpbootDir . '/ipxe_scripts/templates';
     $filePath = "$templateDir/$templateName";
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'params' => ['filePath' => $filePath],
         'desc' => 'Computed file path for template.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     if (!file_exists($filePath)) {
         $httpCode = '404';
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['templateName' => $templateName, 'filePath' => $filePath],
             'desc' => 'Template not found.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new Response(json_encode([
             'error' => 'TEMPLATE_NOT_FOUND',
             'message' => 'No se encontró la plantilla especificada'
         ]), Response::HTTP_NOT_FOUND, ['Content-Type' => 'application/json']);
     }
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'params' => ['filePath' => $filePath],
         'desc' => 'Template found, attempting to read content.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     $content = file_get_contents($filePath);
     if ($content === false) {
         $httpCode = '500';
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['templateName' => $templateName, 'filePath' => $filePath],
             'desc' => 'Failed to read template content.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new Response(json_encode([
             'error' => 'FAILED_TO_READ_TEMPLATE',
             'message' => 'Error al leer la plantilla'
         ]), Response::HTTP_INTERNAL_SERVER_ERROR, ['Content-Type' => 'application/json']);
     }
 
     $httpCode = '200';
     $this->logger->info(json_encode([
         'severity' => 'INFO',
         'operation' => $operation,
         'component' => $component,
         'http_code' => $httpCode,
         'params' => ['templateName' => $templateName],
         'desc' => 'Template retrieved successfully.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'params' => ['templateContent' => $content],
         'desc' => 'Template content retrieved.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     return new Response(json_encode([
         'success' => 'Plantilla obtenida con éxito',
         'template_name' => $templateName,
         'template_content' => $content
     ]), Response::HTTP_OK, ['Content-Type' => 'application/json']);
 }
 
    

/**
 * @Route("/ogboot/v1/pxe-templates", methods={"POST"})
 * 
 * @OA\Post(
 *     path="/ogboot/v1/pxe-templates",
 *     summary="Crear Plantilla",
 *     description="Crea una nueva plantilla de arranque utilizando los datos proporcionados.",
 *     @OA\RequestBody(
 *         required=true,
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="name_template", type="string", example="mi_plantilla.ipxe"),
 *             @OA\Property(property="content_template", type="string", example="#!ipxe\nset timeout 0\nset timeout-style hidden\nset ISODIR __OGLIVE__\nset default 0\nset kernelargs __INFOHOST__\n:try_iso\nkernel http://__SERVERIP__/tftpboot/${ISODIR}/ogvmlinuz ${kernelargs} || goto fallback\ninitrd http://__SERVERIP__/tftpboot/${ISODIR}/oginitrd.img\nboot\n\n:fallback\nset ISODIR ogLive\nkernel http://__SERVERIP__/tftpboot/${ISODIR}/ogvmlinuz ${kernelargs}\ninitrd http://__SERVERIP__/tftpboot/${ISODIR}/oginitrd.img\nboot\n")
 *         )
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="La plantilla de arranque se creó exitosamente.",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="success", type="string", example="Plantilla creada con éxito"),
 *             @OA\Property(
 *                 property="message",
 *                 type="object",
 *                 @OA\Property(property="template_name", type="string", example="mi_plantilla.ipxe"),
 *                 @OA\Property(property="template_content", type="string", example="#!ipxe\nset timeout 0\nset timeout-style hidden\nset ISODIR __OGLIVE__\nset default 0\nset kernelargs __INFOHOST__\n:try_iso\nkernel http://__SERVERIP__/tftpboot/${ISODIR}/ogvmlinuz ${kernelargs} || goto fallback\ninitrd http://__SERVERIP__/tftpboot/${ISODIR}/oginitrd.img\nboot\n\n:fallback\nset ISODIR ogLive\nkernel http://__SERVERIP__/tftpboot/${ISODIR}/ogvmlinuz ${kernelargs}\ninitrd http://__SERVERIP__/tftpboot/${ISODIR}/oginitrd.img\nboot\n")
 *             )
 *         )
 *     ),
 *     @OA\Response(
 *         response=400,
 *         description="Datos no válidos. Faltan los parámetros 'name_template' o 'content_template'.",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="INVALID_INPUT"),
 *             @OA\Property(property="message", type="string", example="Faltan datos requeridos: name_template y content_template son necesarios.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=403,
 *         description="Intento de acceso no autorizado fuera del directorio de plantillas.",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="UNAUTHORIZED_ACCESS"),
 *             @OA\Property(property="message", type="string", example="Intento de acceso no autorizado fuera del directorio de plantillas.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Ocurrió un error al crear la plantilla de arranque.",
 *         @OA\JsonContent(
 *             type="object",
 *             @OA\Property(property="error", type="string", example="FILE_CREATION_ERROR"),
 *             @OA\Property(property="message", type="string", example="Ocurrió un error al crear la plantilla de arranque.")
 *         )
 *     )
 * )
 */

 public function createTemplate(Request $request): JsonResponse
 {
     $operation = 'ogboot.createTemplate';
     $component = 'ogboot';
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'desc' => 'Attempting to create a new template.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     $data = json_decode($request->getContent(), true);
 
     if (!isset($data['name_template']) || !isset($data['content_template'])) {
         $httpCode = '400';
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['requestData' => $data],
             'desc' => 'Missing required fields: name_template or content_template.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse([
             'error' => 'INVALID_INPUT',
             'message' => 'Faltan datos requeridos: name_template y content_template son necesarios.'
         ], JsonResponse::HTTP_BAD_REQUEST);
     }
 
     $nameTemplate = $data['name_template'];
     $contentTemplate = $data['content_template'];
     $templateDir = $this->tftpbootDir . '/ipxe_scripts/templates';
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'params' => ['nameTemplate' => $nameTemplate],
         'desc' => 'Received template data.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     if (!preg_match('/^[a-zA-Z0-9._-]+$/', $nameTemplate)) {
         $httpCode = '400';
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['nameTemplate' => $nameTemplate],
             'desc' => 'Invalid template name. Contains invalid characters.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse([
             'error' => 'INVALID_TEMPLATE_NAME',
             'message' => 'El nombre de la plantilla contiene caracteres no válidos.'
         ], JsonResponse::HTTP_BAD_REQUEST);
     }
 
     $filePath = $templateDir . '/' . $nameTemplate;
     $realFilePath = realpath($templateDir) . '/' . $nameTemplate;
 
     $this->logger->debug(json_encode([
         'severity' => 'DEBUG',
         'operation' => $operation,
         'component' => $component,
         'params' => ['filePath' => $filePath, 'realFilePath' => $realFilePath],
         'desc' => 'Computed file paths for template.'
     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     if (strpos($realFilePath, realpath($templateDir)) !== 0) {
         $httpCode = '403';
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['nameTemplate' => $nameTemplate, 'filePath' => $filePath],
             'desc' => 'Unauthorized access attempt outside the template directory.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse([
             'error' => 'UNAUTHORIZED_ACCESS',
             'message' => 'Intento de acceso no autorizado fuera del directorio de plantillas.'
         ], JsonResponse::HTTP_FORBIDDEN);
     }
 
     $contentTemplate = str_replace("\\n", "\n", $contentTemplate);
 
     try {
         $this->logger->info(json_encode([
             'severity' => 'INFO',
             'operation' => $operation,
             'component' => $component,
             'params' => ['filePath' => $realFilePath],
             'desc' => 'Attempting to create the template file.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         file_put_contents($realFilePath, $contentTemplate);
 
         if (!file_exists($realFilePath)) {
             throw new \Exception('El archivo no se pudo crear.');
         }
 
         $writtenContent = file_get_contents($realFilePath);
         if ($writtenContent !== $contentTemplate) {
             throw new \Exception('El contenido del archivo no coincide con el contenido esperado.');
         }
 
         $httpCode = '200';
         $this->logger->info(json_encode([
             'severity' => 'INFO',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['filePath' => $realFilePath],
             'desc' => 'Template created successfully.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
     } catch (\Exception $e) {
         $httpCode = '500';
         $this->logger->error(json_encode([
             'severity' => 'ERROR',
             'operation' => $operation,
             'component' => $component,
             'http_code' => $httpCode,
             'params' => ['nameTemplate' => $nameTemplate, 'filePath' => $realFilePath, 'exception' => $e->getMessage()],
             'desc' => 'Failed to create template.'
         ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
 
         return new JsonResponse([
             'error' => 'FILE_CREATION_ERROR',
             'message' => 'Ocurrió un error al crear la plantilla de arranque: ' . $e->getMessage()
         ], JsonResponse::HTTP_INTERNAL_SERVER_ERROR);
     }
 
     return new JsonResponse([
         'success' => 'Plantilla creada con éxito',
         'message' => [
             'template_name' => $nameTemplate,
             'template_content' => $contentTemplate
         ]
     ], JsonResponse::HTTP_OK);
 }
 



/**
 * @Route("/ogboot/v1/pxe-templates/{name}", methods={"DELETE"})
 * 
 * @OA\Delete(
 *     path="/ogboot/v1/pxe-templates/{name}",
 *     summary="Eliminar Plantilla",
 *     description="Elimina una plantilla de arranque específica utilizando su nombre.",
 *     @OA\Parameter(
 *         name="name",
 *         in="path",
 *         required=true,
 *         description="El nombre de la plantilla de arranque que se desea eliminar.",
 *         @OA\Schema(type="string")
 *     ),
 *     @OA\Response(
 *         response=200,
 *         description="La plantilla de arranque se eliminó correctamente.",
 *         @OA\JsonContent(
 *             @OA\Property(property="success", type="string", example="Plantilla eliminada"),
 *             @OA\Property(property="message", type="string", example="La plantilla mi_plantilla se ha borrado correctamente.")
 *         )
 *     ),
 *     @OA\Response(
 *         response=404,
 *         description="No se encontró ninguna plantilla de arranque con el nombre especificado.",
 *         @OA\JsonContent(
 *             @OA\Property(property="error", type="string", example="TEMPLATE_NOT_FOUND"),
 *             @OA\Property(property="message", type="string", example="No se encontró la plantilla especificada")
 *         )
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Ocurrió un error al eliminar la plantilla de arranque.",
 *         @OA\JsonContent(
 *             @OA\Property(property="error", type="string", example="FAILED_TO_DELETE_TEMPLATE"),
 *             @OA\Property(property="message", type="string", example="Ocurrió un error al intentar eliminar la plantilla")
 *         )
 *     )
 * )
 */
public function deleteTemplate(string $name): Response
{
    $operation = 'ogboot.deleteTemplate';
    $component = 'ogboot';

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['templateName' => $name],
        'desc' => 'Attempting to delete template.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $templateDir = $this->tftpbootDir . '/ipxe_scripts/templates';
    $filePath = $templateDir . '/' . $name;

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['filePath' => $filePath],
        'desc' => 'Computed file path for template.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    if (!file_exists($filePath)) {
        $httpCode = '404';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['templateName' => $name, 'filePath' => $filePath],
            'desc' => 'Template not found.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new Response(json_encode([
            'error' => 'TEMPLATE_NOT_FOUND',
            'message' => 'No se encontró la plantilla especificada'
        ]), Response::HTTP_NOT_FOUND, ['Content-Type' => 'application/json']);
    }

    $this->logger->debug(json_encode([
        'severity' => 'DEBUG',
        'operation' => $operation,
        'component' => $component,
        'params' => ['filePath' => $filePath],
        'desc' => 'Template exists. Proceeding to delete.'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    try {
        unlink($filePath);

        $httpCode = '200';
        $this->logger->info(json_encode([
            'severity' => 'INFO',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['templateName' => $name, 'filePath' => $filePath],
            'desc' => 'Template deleted successfully.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    } catch (\Exception $e) {
        $httpCode = '500';
        $this->logger->error(json_encode([
            'severity' => 'ERROR',
            'operation' => $operation,
            'component' => $component,
            'http_code' => $httpCode,
            'params' => ['templateName' => $name, 'filePath' => $filePath, 'exception' => $e->getMessage()],
            'desc' => 'Failed to delete template.'
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        return new Response(json_encode([
            'error' => 'FAILED_TO_DELETE_TEMPLATE',
            'message' => 'Ocurrió un error al intentar eliminar la plantilla'
        ]), Response::HTTP_INTERNAL_SERVER_ERROR, ['Content-Type' => 'application/json']);
    }

    return new Response(json_encode([
        'success' => 'Plantilla eliminada',
        'message' => "La plantilla $name se ha borrado correctamente"
    ]), Response::HTTP_OK, ['Content-Type' => 'application/json']);
}




}



