<?php

declare(strict_types=1);

namespace Tests\Unit\Application\GraphQL;

use App\Application\GraphQL\GraphQLPlaygroundController;
use App\Framework\Config\Environment;
use App\Framework\Config\EnvKey;
use App\Framework\Http\Method;
use App\Framework\Http\Request\HttpRequest;
use App\Framework\Http\ServerEnvironment;
use App\Framework\Router\Result\ViewResult;

describe('GraphQLPlaygroundController', function () {
    beforeEach(function () {
        // Create test environment with array
        $this->environment = new Environment([
            'APP_DEBUG' => true,
        ]);

        // Mock HttpRequest
        $this->createRequest = function (bool $isSecure = false, string $host = 'localhost') {
            $serverEnv = new class($isSecure, $host) extends ServerEnvironment {
                public function __construct(
                    private bool $isSecure,
                    private string $host
                ) {
                    parent::__construct([
                        'HTTPS' => $isSecure ? 'on' : 'off',
                        'HTTP_HOST' => $host,
                        'SERVER_PROTOCOL' => 'HTTP/1.1',
                        'REQUEST_METHOD' => 'GET',
                        'REQUEST_URI' => '/graphql/playground',
                    ]);
                }

                public function isSecure(): bool
                {
                    return $this->isSecure;
                }

                public function getHttpHost(): string
                {
                    return $this->host;
                }
            };

            return new HttpRequest(
                method: Method::GET,
                uri: '/graphql/playground',
                server: $serverEnv,
                headers: new \App\Framework\Http\Headers([]),
                cookies: new \App\Framework\Http\Cookies([]),
                query: new \App\Framework\Http\QueryParameters([]),
                parsedBody: null
            );
        };

        $this->controller = new GraphQLPlaygroundController($this->environment);
    });

    it('returns playground view in development mode', function () {

        $request = ($this->createRequest)();
        $result = $this->controller->playground($request);

        expect($result)->toBeInstanceOf(ViewResult::class);
        expect($result->template)->toBe('graphql/playground');
    });

    it('includes GraphQL endpoints in view data', function () {
        $request = ($this->createRequest)(isSecure: false, host: 'localhost');
        $result = $this->controller->playground($request);

        expect($result->data['graphql_endpoint'])->toBe('http://localhost/graphql');
        expect($result->data['graphql_ws_endpoint'])->toBe('ws://localhost/graphql');
        expect($result->data['graphql_schema_endpoint'])->toBe('http://localhost/graphql/schema');
    });

    it('uses HTTPS/WSS for secure connections', function () {
        $request = ($this->createRequest)(isSecure: true, host: 'example.com');
        $result = $this->controller->playground($request);

        expect($result->data['graphql_endpoint'])->toBe('https://example.com/graphql');
        expect($result->data['graphql_ws_endpoint'])->toBe('wss://example.com/graphql');
        expect($result->data['graphql_schema_endpoint'])->toBe('https://example.com/graphql/schema');
    });

    it('throws exception when not in development mode', function () {
        // Create production environment with APP_DEBUG=false
        $prodEnvironment = new Environment(['APP_DEBUG' => false]);
        $prodController = new GraphQLPlaygroundController($prodEnvironment);

        $request = ($this->createRequest)();

        expect(fn() => $prodController->playground($request))
            ->toThrow(\RuntimeException::class, 'GraphQL Playground is only available in development mode');
    });

    it('works with different hostnames', function () {
        $request = ($this->createRequest)(isSecure: true, host: 'api.example.com:8443');
        $result = $this->controller->playground($request);

        expect($result->data['graphql_endpoint'])->toBe('https://api.example.com:8443/graphql');
        expect($result->data['graphql_ws_endpoint'])->toBe('wss://api.example.com:8443/graphql');
    });
});
