<?php

namespace Tests\Feature;

use Fruitcake\Cors\CorsService;
use Illuminate\Http\Middleware\HandleCors;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Tests\TestCase;

class SecurityHeadersTest extends TestCase
{
    public function test_marketing_and_auth_responses_have_security_headers_and_csrf_cookie(): void
    {
        $originalEnv = app()->environment();
        app()->detectEnvironment(fn () => 'production');
        config([
            'app.debug' => false,
            'app.url' => 'https://test-y0k0.fotospiel.app',
            'security_headers.force_hsts' => true,
            'cors.allowed_origins' => ['https://test-y0k0.fotospiel.app'],
            'cors.paths' => ['*'],
        ]);

        Route::middleware('web')->get('/__test/marketing', fn () => response('ok'));
        Route::middleware('web')->get('/__test/auth', fn () => response('ok'));

        try {
            $response = $this->withServerVariables([
                'HTTPS' => 'on',
                'HTTP_ORIGIN' => 'https://test-y0k0.fotospiel.app',
            ])->get('/__test/marketing');

            $response->assertOk();
            $response->assertHeader('X-Frame-Options', 'SAMEORIGIN');
            $response->assertHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
            $response->assertHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
            $response->assertHeader('Content-Security-Policy');
            $response->assertHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
            $response->assertCookie('XSRF-TOKEN');

            $login = $this->withServerVariables([
                'HTTPS' => 'on',
                'HTTP_ORIGIN' => 'https://test-y0k0.fotospiel.app',
            ])->get('/__test/auth');

            $login->assertOk();
            $login->assertHeader('Content-Security-Policy');
            $login->assertHeader('X-Frame-Options', 'SAMEORIGIN');
            $login->assertCookie('XSRF-TOKEN');
        } finally {
            app()->detectEnvironment(fn () => $originalEnv);
        }
    }

    public function test_cors_headers_present_for_api_requests_and_error_responses_keep_headers(): void
    {
        $originalEnv = app()->environment();
        app()->detectEnvironment(fn () => 'production');
        $corsConfig = config('cors');
        $corsConfig['paths'] = ['*'];
        $corsConfig['allowed_origins'] = ['https://test-y0k0.fotospiel.app'];

        config([
            'app.debug' => false,
            'app.url' => 'https://test-y0k0.fotospiel.app',
            'cors' => $corsConfig,
        ]);

        Route::middleware('web')->get('/__test/error', fn () => throw new \RuntimeException('boom'));

        try {
            $corsMiddleware = new HandleCors(app(), new CorsService(config('cors')));
            $this->assertContains('*', config('cors.paths'));
            $this->assertContains('https://test-y0k0.fotospiel.app', config('cors.allowed_origins'));
            $corsRequest = Request::create(
                uri: '/api/__test/cors',
                method: 'OPTIONS',
                server: [
                    'HTTP_ORIGIN' => 'https://test-y0k0.fotospiel.app',
                    'HTTPS' => 'on',
                    'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET',
                ],
            );

            $this->assertSame('https://test-y0k0.fotospiel.app', $corsRequest->headers->get('Origin'));

            $corsResponse = $corsMiddleware->handle($corsRequest, fn () => response()->noContent());

            $this->assertSame('https://test-y0k0.fotospiel.app', $corsResponse->headers->get('Access-Control-Allow-Origin'));

            $error = $this->withServerVariables([
                'HTTPS' => 'on',
            ])->get('/__test/error');

            $error->assertStatus(500);
            $error->assertHeader('Content-Security-Policy');
            $error->assertHeader('X-Frame-Options', 'SAMEORIGIN');
        } finally {
            app()->detectEnvironment(fn () => $originalEnv);
        }
    }

    public function test_guest_pwa_allows_camera_via_permissions_policy(): void
    {
        $originalEnv = app()->environment();
        app()->detectEnvironment(fn () => 'production');
        config([
            'app.debug' => false,
            'app.url' => 'https://test-y0k0.fotospiel.app',
            'security_headers.force_hsts' => true,
        ]);

        Route::middleware('web')->get('/e/test-token', fn () => response('ok'));

        try {
            $response = $this->withServerVariables([
                'HTTPS' => 'on',
                'HTTP_ORIGIN' => 'https://test-y0k0.fotospiel.app',
            ])->get('/e/test-token');

            $response->assertOk();
            $response->assertHeader('Permissions-Policy', 'camera=(self), microphone=(), geolocation=()');
        } finally {
            app()->detectEnvironment(fn () => $originalEnv);
        }
    }
}
