<?php
// src/OgGitBundle/Controller/OgGitController.php

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


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

    private $ogGitService;
    private $httpClient;
    private $params;
    public function __construct(OgGitService $ogGitService, LoggerInterface $logger, HttpClientInterface $httpClient, ParameterBagInterface $params)
    {
        $this->ogGitService = $ogGitService;
        $this->logger = $logger;
        $this->httpClient = $httpClient;
        $this->params = $params;
    }




    /**
     * @Route("/oggit/v1/repositories", methods={"GET"})
     * @OA\Get(
     *     path="/oggit/v1/repositories",
     *     summary="Obtener un listado de todos los repositorios alojados en el servidor OG",
     *     tags={"Repositories"},
     *     @OA\Response(
     *         response=200,
     *         description="Lista de repositorios obtenida con éxito",
     *         @OA\JsonContent(
     *             type="array",
     *             @OA\Items(
     *                 type="object",
     *                 @OA\Property(property="name", type="string", description="Nombre del repositorio")
     *             )
     *         )
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al conectar con el servicio externo"
     *     )
     * )
     */
    public function getRepositories(): JsonResponse
    {
        // Hacer la solicitud al servicio Python utilizando makeRequest
        $response = $this->ogGitService->makeRequest('GET', '/repositories');

        // Verificar si la solicitud al servicio Python falló
        if (isset($response['error'])) {
            return new JsonResponse(['error' => 'No se pudo conectar con el servicio externo'], 500);
        }

        // Devolver la lista de repositorios
        return new JsonResponse($response, 200);
    }


    /**
     * @Route("/oggit/v1/repositories", methods={"POST"})
     * @OA\Post(
     *     path="/oggit/v1/repositories",
     *     summary="Crear un nuevo repositorio",
     *     tags={"Repositories"},
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="name", type="string", description="Nombre del repositorio")
     *         )
     *     ),
     *     @OA\Response(
     *         response=201,
     *         description="Repositorio creado con éxito"
     *     ),
     *     @OA\Response(
     *         response=400,
     *         description="Nombre de repositorio inválido"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al conectar con el servicio externo"
     *     )
     * )
     */
    public function createRepository(Request $request): JsonResponse
    {
        // Obtener el contenido JSON del cuerpo de la solicitud
        $data = json_decode($request->getContent(), true);
        $name = $data['name'] ?? '';

        // Validar el nombre del repositorio usando isValidBranchName
        if (!$this->ogGitService->isValidBranchName($name)) {
            return new JsonResponse(['error' => 'Nombre de repositorio inválido'], 400);
        }

        // Hacer la solicitud para crear el repositorio
        $response = $this->ogGitService->makeRequest('PUT', "/repositories/{$name}");

        // Manejar la respuesta en función de si el repositorio fue creado o ya existía
        if ($response['status'] === 'Repository created') {
            return new JsonResponse(['message' => 'Repositorio creado con éxito'], 201);
        } elseif ($response['status'] === 'Repository already exists') {
            return new JsonResponse(['message' => 'El repositorio ya existe'], 200);
        }

        // Respuesta por defecto en caso de otro resultado inesperado
        return new JsonResponse(['error' => 'Error desconocido'], 500);
    }
    
    /**
     * @Route("/oggit/v1/repositories/{repoId}", methods={"DELETE"})
     * @OA\Delete(
     *     path="/oggit/v1/repositories/{repoId}",
     *     tags={"Repositories"},
     *     summary="Eliminar un repositorio",
     *     @OA\Parameter(
     *         name="repoId",
     *         in="path",
     *         required=true,
     *         description="ID del repositorio a eliminar",
     *         example="linux.git",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Repositorio eliminado exitosamente"
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Repositorio no encontrado"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al conectar con el servicio externo"
     *     )
     * )
     */
    public function deleteRepository($repoId): JsonResponse
    {
        // Hacer la solicitud al servicio externo para eliminar el repositorio
        $response = $this->ogGitService->makeRequest('DELETE', "/repositories/{$repoId}");

        // Comprobar si la solicitud falló
        if (isset($response['error'])) {
            return new JsonResponse(['error' => 'No se pudo conectar con el servicio externo'], 500);
        }

        // Manejar la respuesta del servicio externo
        if (isset($response['status']) && $response['status'] === 'Repository deleted') {
            return new JsonResponse(['message' => 'Repositorio eliminado exitosamente'], 200);
        }

        // Devolver exactamente lo que devuelve tu compañero, incluyendo 404
        if (isset($response['error']) && $response['error'] === 'Repository not found') {
            return new JsonResponse(['error' => 'Repository not found'], 404);
        }

        // Respuesta por defecto en caso de un error inesperado
        return new JsonResponse(['error' => 'Error desconocido'], 500);
    }

    /**
     * @Route("/oggit/v1/repositories/{repoId}/compact", methods={"POST"})
     * @OA\Post(
     *     path="/oggit/v1/repositories/{repoId}/compact",
     *     summary="Realizar la compactación del repositorio Git",
     *     tags={"Repositories"},
     *     @OA\Parameter(
     *         name="repoId",
     *         in="path",
     *         required=true,
     *         description="ID del repositorio para compactar",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Compactación realizada con éxito"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al realizar la compactación"
     *     )
     * )
     */
    public function compactRepository($repoId): JsonResponse
    {
        // Llamar a la función del servicio para compactar el repositorio
        $result = $this->ogGitService->makeRequest('POST', '/repositories/' . $repoId . '/compact');

        if ($result['success']) {
            return new JsonResponse(['message' => "Compactación realizada con éxito para el repositorio: {$repoId}"], 200);
        }

        return new JsonResponse(['error' => 'Error al realizar la compactación'], 500);
    }

    /**
     * @Route("/oggit/v1/repositories/{repoId}/sync", methods={"POST"})
     * @OA\Post(
     *     path="/oggit/v1/repositories/{repoId}/sync",
     *     summary="Sincronizar un repositorio con otro",
     *     tags={"Repositories"},
     *     @OA\Parameter(
     *         name="repoId",
     *         in="path",
     *         required=true,
     *         description="ID del repositorio a sincronizar",
     *         example="linux",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="remote_repository", type="string", description="Repositorio remoto")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Sincronización iniciada"
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Repositorio no encontrado"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al conectar con el servicio externo"
     *     )
     * )
     */
    public function syncRepository(Request $request, $repoId): JsonResponse
    {
        // Obtener los datos del cuerpo de la solicitud
        $data = json_decode($request->getContent(), true);
        $remoteRepository = $data['remote_repository'] ?? '';

        // Hacer la solicitud al servicio externo para la sincronización
        $response = $this->ogGitService->makeRequest('POST', "/repositories/{$repoId}/sync", [
            'json' => ['remote_repository' => $remoteRepository]
        ]);

        // Comprobar si la solicitud falló
        if (isset($response['error'])) {
            return new JsonResponse(['error' => 'No se pudo conectar con el servicio externo'], 500);
        }

        // Manejar la respuesta del servicio externo
        if (isset($response['status']) && $response['status'] === 'Started synchronization') {
            return new JsonResponse([
                'message' => 'Sincronización iniciada',
                'repository' => $repoId,
                'remote_repository' => $remoteRepository
            ], 200);
        }

        // Devolver 404 si el repositorio no se encuentra
        if (isset($response['error']) && $response['error'] === 'Repository not found') {
            return new JsonResponse(['error' => 'Repository not found'], 404);
        }

        return new JsonResponse(['error' => 'Error desconocido'], 500);
    }

    /**
     * @Route("/oggit/v1/repositories/{repoId}/sync/status", methods={"GET"})
     * @OA\Get(
     *     path="/oggit/v1/repositories/{repoId}/sync/status",
     *     summary="Consultar el estado de la sincronización de un repositorio",
     *     tags={"Repositories"},
     *     @OA\Parameter(
     *         name="repoId",
     *         in="path",
     *         required=true,
     *         description="ID del repositorio a consultar",
     *         example="linux",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="remote_repository", type="string", description="Repositorio remoto")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Estado de la sincronización consultado con éxito"
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Repositorio no encontrado"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al conectar con el servicio externo"
     *     )
     * )
     */
    public function getSyncStatus(Request $request, $repoId): JsonResponse
    {
        // Obtener los datos del cuerpo de la solicitud
        $data = json_decode($request->getContent(), true);
        $remoteRepository = $data['remote_repository'] ?? '';

        // Hacer la solicitud al servicio externo para consultar el estado de sincronización
        $response = $this->ogGitService->makeRequest('GET', "/repositories/{$repoId}/sync/status", [
            'json' => ['remote_repository' => $remoteRepository]
        ]);

        // Comprobar si la solicitud falló
        if (isset($response['error'])) {
            return new JsonResponse(['error' => 'No se pudo conectar con el servicio externo'], 500);
        }

        return new JsonResponse($response, 200);
    }
    /**
     * @Route("/oggit/v1/repositories/{repoId}/backup", methods={"POST"})
     * @OA\Post(
     *     path="/oggit/v1/repositories/{repoId}/backup",
     *     summary="Realizar una copia de seguridad de un repositorio",
     *     tags={"Repositories"},
     *     @OA\Parameter(
     *         name="repoId",
     *         in="path",
     *         required=true,
     *         description="ID del repositorio a respaldar",
     *         example="linux",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="ssh_server", type="string", description="Servidor SSH"),
     *             @OA\Property(property="ssh_user", type="string", description="Usuario SSH"),
     *             @OA\Property(property="filename", type="string", description="Archivo de destino")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Copia de seguridad iniciada"
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Repositorio no encontrado"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al conectar con el servicio externo"
     *     )
     * )
     */
    public function backupRepository(Request $request, $repoId): JsonResponse
    {
        // Obtener los datos del cuerpo de la solicitud
        $data = json_decode($request->getContent(), true);
        $sshServer = $data['ssh_server'] ?? '';
        $sshUser = $data['ssh_user'] ?? '';
        $filename = $data['filename'] ?? '';

        // Hacer la solicitud al servicio externo para la copia de seguridad
        $response = $this->ogGitService->makeRequest('POST', "/repositories/{$repoId}/backup", [
            'json' => [
                'ssh_server' => $sshServer,
                'ssh_user' => $sshUser,
                'filename' => $filename
            ]
        ]);

        // Comprobar si la solicitud falló
        if (isset($response['error'])) {
            return new JsonResponse(['error' => 'No se pudo conectar con el servicio externo'], 500);
        }

        // Manejar la respuesta del servicio externo y devolver los valores del response
        if (isset($response['status']) && $response['status'] === 'Started backup') {
            return new JsonResponse([
                'message' => 'Copia de seguridad iniciada',
                'repository' => $repoId,
                'ssh_server' => $response['ssh_server'],
                'ssh_user' => $response['ssh_user'],
                'filename' => $response['filename']
            ], 200);
        }
        // Devolver 404 si el repositorio no se encuentra
        if (isset($response['error']) && $response['error'] === 'Repository not found') {
            return new JsonResponse(['error' => 'Repository not found'], 404);
        }

        return new JsonResponse(['error' => 'Error desconocido'], 500);
    }
   /**
     * @Route("/oggit/v1/repositories/{repoId}/backup/status", methods={"GET"})
     * @OA\Get(
     *     path="/oggit/v1/repositories/{repoId}/backup/status",
     *     summary="Consultar el estado de la copia de seguridad de un repositorio",
     *     tags={"Repositories"},
     *     @OA\Parameter(
     *         name="repoId",
     *         in="path",
     *         required=true,
     *         description="ID del repositorio a consultar",
     *         example="linux",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="ssh_server", type="string", description="Servidor SSH"),
     *             @OA\Property(property="ssh_user", type="string", description="Usuario SSH"),
     *             @OA\Property(property="filename", type="string", description="Archivo de destino")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Estado de la copia de seguridad consultado con éxito"
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Repositorio no encontrado"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al conectar con el servicio externo"
     *     )
     * )
     */
    public function getBackupStatus(Request $request, $repoId): JsonResponse
    {
        // Obtener los datos del cuerpo de la solicitud
        $data = json_decode($request->getContent(), true);
        $sshServer = $data['ssh_server'] ?? '';
        $sshUser = $data['ssh_user'] ?? '';
        $filename = $data['filename'] ?? '';

        // Hacer la solicitud al servicio externo para consultar el estado de la copia de seguridad
        $response = $this->ogGitService->makeRequest('GET', "/repositories/{$repoId}/backup/status", [
            'json' => [
                'ssh_server' => $sshServer,
                'ssh_user' => $sshUser,
                'filename' => $filename
            ]
        ]);

        // Comprobar si la solicitud falló
        if (isset($response['error'])) {
            return new JsonResponse(['error' => 'No se pudo conectar con el servicio externo'], 500);
        }

        return new JsonResponse($response, 200);
    }
    /**
     * @Route("/oggit/v1/repositories/{repoId}/branches", methods={"GET"})
     * @OA\Get(
     *     path="/oggit/v1/repositories/{repoId}/branches",
     *     summary="Obtener las ramas de un repositorio",
     *     tags={"Branches"},
     *     @OA\Parameter(
     *         name="repoId",
     *         in="path",
     *         required=true,
     *         description="ID del repositorio",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Lista de ramas obtenida con éxito"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al obtener las ramas"
     *     )
     * )
     */
    public function getBranches($repoId): JsonResponse
    {
        // Llamar a la función makeRequest del servicio OgGitService
        $response = $this->ogGitService->makeRequest('GET', "/repositories/{$repoId}/branches");

        if (isset($response['branches'])) {
            return new JsonResponse(['branches' => $response['branches']], 200);
        }

        return new JsonResponse(['error' => 'No se pudieron obtener las ramas del repositorio'], 500);
    }

    /**
     * @Route("/oggit/v1/repositories/{repoId}/branches", methods={"POST"})
     * @OA\Post(
     *     path="/oggit/v1/repositories/{repoId}/branches",
     *     summary="Crear una nueva rama en un repositorio",
     *     tags={"Branches"},
     *     @OA\Parameter(
     *         name="repoId",
     *         in="path",
     *         required=true,
     *         description="ID del repositorio",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="branchName", type="string", description="Nombre de la nueva rama")
     *         )
     *     ),
     *     @OA\Response(
     *         response=201,
     *         description="Rama creada con éxito"
     *     ),
     *     @OA\Response(
     *         response=400,
     *         description="Nombre de rama inválido"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al conectar con el servicio externo"
     *     )
     * )
     */
    public function createBranch(Request $request, $repoId): JsonResponse
    {
        // Obtener el contenido JSON del cuerpo de la solicitud
        $data = json_decode($request->getContent(), true);
        $branchName = $data['branchName'] ?? '';

        // Validar el nombre de la rama usando isValidBranchName
        if (!$this->ogGitService->isValidBranchName($branchName)) {
            return new JsonResponse(['error' => 'Nombre de rama inválido'], 400);
        }

        // Hacer la solicitud al servicio externo para crear la rama
        $response = $this->ogGitService->makeRequest('POST', "/repositories/{$repoId}/branches/{$branchName}");

        // Comprobar si la solicitud falló
        if (isset($response['error'])) {
            return new JsonResponse(['error' => 'No se pudo conectar con el servicio externo'], 500);
        }

        // Manejar la respuesta del servicio externo
        if (isset($response['status']) && $response['status'] === 'Branch created') {
            return new JsonResponse([
                'message' => 'Rama creada con éxito',
                'branchName' => $response['branchName'],
                'repository' => $response['repoId']
            ], 201);
        }

        // Devolver 404 si el repositorio no se encuentra
        if (isset($response['error']) && $response['error'] === 'Repository not found') {
            return new JsonResponse(['error' => 'Repository not found'], 404);
        }

        return new JsonResponse(['error' => 'Error desconocido'], 500);
    }

    /**
     * @Route("/oggit/v1/repositories/{repoId}/branches/{branchId}", methods={"DELETE"})
     * @OA\Delete(
     *     path="/oggit/v1/repositories/{repoId}/branches/{branchId}",
     *     summary="Eliminar una rama de un repositorio",
     *     tags={"Branches"},
     *     @OA\Parameter(
     *         name="repoId",
     *         in="path",
     *         required=true,
     *         description="ID del repositorio",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Parameter(
     *         name="branchId",
     *         in="path",
     *         required=true,
     *         description="ID de la rama a eliminar",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Response(
     *         response=204,
     *         description="Rama eliminada exitosamente"
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Repositorio o rama no encontrada"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Error al conectar con el servicio externo"
     *     )
     * )
     */
    public function deleteBranch($repoId, $branchId): JsonResponse
    {
        // Hacer la solicitud al servicio externo para eliminar la rama
        $response = $this->ogGitService->makeRequest('DELETE', "/repositories/{$repoId}/branches/{$branchId}");

        // Comprobar si la solicitud falló
        if (isset($response['error'])) {
            return new JsonResponse(['error' => 'No se pudo conectar con el servicio externo'], 500);
        }

        // Manejar la respuesta del servicio externo
        if (isset($response['status']) && $response['status'] === 'Branch deleted') {
            return new JsonResponse(['message' => 'Rama eliminada exitosamente'], 204);
        }

        // Devolver 404 si el repositorio o la rama no se encuentran
        if (isset($response['error']) && $response['error'] === 'Repository or branch not found') {
            return new JsonResponse(['error' => 'Repository or branch not found'], 404);
        }

        return new JsonResponse(['error' => 'Error desconocido'], 500);
    }

}