<?php

declare(strict_types=1);

namespace App\Application\Http;

use App\Framework\Attributes\Route;
use App\Framework\Exception\FrameworkException;
use App\Framework\Http\Batch\BatchProcessor;
use App\Framework\Http\Batch\BatchRequest;
use App\Framework\Http\Headers;
use App\Framework\Http\HttpResponse;
use App\Framework\Http\Method;
use App\Framework\Http\Request;
use App\Framework\Http\Status;
use App\Framework\Serializer\Json\JsonSerializer;
use App\Framework\Serializer\Json\JsonSerializerConfig;

/**
 * Controller for handling batch API requests
 */
final readonly class BatchController
{
    public function __construct(
        private BatchProcessor $batchProcessor,
        private JsonSerializer $jsonSerializer
    ) {
    }

    #[Route(path: '/api/batch', method: Method::POST)]
    public function processBatch(Request $request): HttpResponse
    {
        try {
            // Validate content type
            $contentType = $request->headers->getFirst('Content-Type') ?? '';
            if (! str_contains($contentType, 'application/json')) {
                return $this->errorResponse(
                    'Content-Type must be application/json',
                    Status::BAD_REQUEST
                );
            }

            // Parse batch request
            $batchData = $this->jsonSerializer->deserialize($request->body);
            if (! is_array($batchData)) {
                return $this->errorResponse(
                    'Invalid JSON structure',
                    Status::BAD_REQUEST
                );
            }

            $batchRequest = BatchRequest::fromArray($batchData);

            // Process batch operations
            $responses = $this->batchProcessor->process($batchRequest);

            // Return batch responses
            $responseData = [
                'responses' => array_map(fn ($response) => $response->toArray(), $responses),
                'total' => count($responses),
                'successful' => count(array_filter($responses, fn ($r) => $r->error === null)),
                'failed' => count(array_filter($responses, fn ($r) => $r->error !== null)),
            ];

            return new HttpResponse(
                status: Status::OK,
                headers: new Headers(['Content-Type' => 'application/json']),
                body: $this->jsonSerializer->serialize(
                    $responseData,
                    JsonSerializerConfig::pretty()
                )
            );

        } catch (FrameworkException $e) {
            return $this->errorResponse($e->getMessage(), Status::BAD_REQUEST);
        } catch (\Throwable $e) {
            return $this->errorResponse(
                'Internal server error',
                Status::INTERNAL_SERVER_ERROR
            );
        }
    }

    #[Route(path: '/api/batch/info', method: Method::GET)]
    public function getBatchInfo(Request $request): HttpResponse
    {
        $info = [
            'max_operations' => 100,
            'max_concurrent_operations' => 10,
            'supported_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
            'continue_on_error_supported' => true,
            'example_request' => [
                'operations' => [
                    [
                        'id' => 'get-user-1',
                        'method' => 'GET',
                        'path' => '/api/users/1',
                        'headers' => ['Authorization' => 'Bearer token'],
                    ],
                    [
                        'id' => 'create-post',
                        'method' => 'POST',
                        'path' => '/api/posts',
                        'headers' => ['Content-Type' => 'application/json'],
                        'body' => '{"title": "Test Post", "content": "Hello World"}',
                    ],
                ],
                'continue_on_error' => false,
            ],
        ];

        return new HttpResponse(
            status: Status::OK,
            headers: new Headers(['Content-Type' => 'application/json']),
            body: $this->jsonSerializer->serialize(
                $info,
                JsonSerializerConfig::pretty()
            )
        );
    }

    private function errorResponse(string $message, Status $status): HttpResponse
    {
        return new HttpResponse(
            status: $status,
            headers: new Headers(['Content-Type' => 'application/json']),
            body: $this->jsonSerializer->serialize(['error' => $message])
        );
    }
}
