<?php

namespace App\State\Provider;

use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\Pagination\TraversablePaginator;
use ApiPlatform\State\ProviderInterface;
use App\Dto\Input\GitRepositoryInput;
use App\Dto\Output\GitRepositoryOutput;
use App\Service\ExternalGitRepositoryService;
use App\Repository\ImageRepositoryRepository;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\RequestStack;

readonly class GitRepositoryProvider implements ProviderInterface
{
    public function __construct(
        private ExternalGitRepositoryService $externalService,
        private ImageRepositoryRepository $imageRepositoryRepository,
        private RequestStack $requestStack
    )
    {
    }

    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
    {
        switch ($operation){
            case $operation instanceof GetCollection:
                return $this->provideCollection($operation, $uriVariables, $context);
            case $operation instanceof Patch:
            case $operation instanceof Put:
                return $this->provideInput($operation, $uriVariables, $context);
            case $operation instanceof Get:
                return $this->provideItem($operation, $uriVariables, $context);
        }
    }

    private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object
    {
        // Obtener el ImageRepository desde los parámetros de la request
        $request = $this->requestStack->getCurrentRequest();
        $repositoryId = $request->query->get('repository');
        
        if (!$repositoryId) {
            throw new \InvalidArgumentException('El parámetro "repository" es requerido');
        }

        $imageRepository = $this->imageRepositoryRepository->find($repositoryId);
        if (!$imageRepository) {
            throw new NotFoundHttpException('ImageRepository no encontrado');
        }

        // Obtener repositorios de la API externa
        $externalRepositories = $this->externalService->getRepositories($imageRepository);
        
        $items = new \ArrayObject();
        foreach ($externalRepositories as $externalData) {
            $gitRepository = $this->externalService->createEntityFromExternalData($externalData, $imageRepository);
            $items[] = new GitRepositoryOutput($gitRepository, $context);
        }

        // Simular paginación básica
        $page = $request->query->getInt('page', 1);
        $limit = $request->query->getInt('limit', 10);
        $offset = ($page - 1) * $limit;
        
        $paginatedItems = array_slice($items->getArrayCopy(), $offset, $limit);
        
        return new TraversablePaginator(
            new \ArrayObject($paginatedItems), 
            $page, 
            $limit, 
            count($items)
        );
    }

    public function provideItem(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
    {
        // Obtener el nombre del repositorio desde los parámetros
        $request = $this->requestStack->getCurrentRequest();
        $repositoryId = $request->query->get('repository');
        $name = $uriVariables['name'] ?? $request->query->get('name');
        
        if (!$repositoryId || !$name) {
            throw new \InvalidArgumentException('Los parámetros "repository" y "name" son requeridos');
        }

        $imageRepository = $this->imageRepositoryRepository->find($repositoryId);
        if (!$imageRepository) {
            throw new NotFoundHttpException('ImageRepository no encontrado');
        }

        // Obtener repositorio específico de la API externa
        $externalData = $this->externalService->getRepository($name, $imageRepository);
        
        if (!$externalData) {
            throw new NotFoundHttpException('GitRepository no encontrado');
        }

        $gitRepository = $this->externalService->createEntityFromExternalData($externalData, $imageRepository);
        return new GitRepositoryOutput($gitRepository);
    }

    public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
    {
        if (isset($uriVariables['name'])) {
            // Para operaciones de actualización, necesitamos obtener el repositorio existente
            $request = $this->requestStack->getCurrentRequest();
            $repositoryId = $request->query->get('repository');
            $name = $uriVariables['name'];
            
            if (!$repositoryId) {
                throw new \InvalidArgumentException('El parámetro "repository" es requerido');
            }

            $imageRepository = $this->imageRepositoryRepository->find($repositoryId);
            if (!$imageRepository) {
                throw new NotFoundHttpException('ImageRepository no encontrado');
            }

            $externalData = $this->externalService->getRepository($name, $imageRepository);
            if (!$externalData) {
                throw new NotFoundHttpException('GitRepository no encontrado');
            }

            $gitRepository = $this->externalService->createEntityFromExternalData($externalData, $imageRepository);
            return new GitRepositoryInput($gitRepository);
        }

        return new GitRepositoryInput();
    }
} 