<?php

declare(strict_types=1);

use App\Framework\Http\Cookies\Cookie;
use App\Framework\Http\Cookies\SameSite;

describe('Cookie', function () {
    it('creates a basic cookie', function () {
        $cookie = new Cookie(
            name: 'test',
            value: 'value123'
        );

        expect($cookie->name)->toBe('test');
        expect($cookie->value)->toBe('value123');
        expect($cookie->partitioned)->toBeFalse();
    });

    it('generates correct Set-Cookie header', function () {
        $cookie = new Cookie(
            name: 'session',
            value: 'abc123',
            expires: 1735689600, // 2025-01-01 00:00:00
            path: '/app',
            domain: 'example.com',
            secure: true,
            httpOnly: true,
            sameSite: SameSite::Strict
        );

        $header = $cookie->toHeaderString();

        expect($header)->toContain('session=abc123');
        expect($header)->toContain('Path=/app');
        expect($header)->toContain('Domain=example.com');
        expect($header)->toContain('Secure');
        expect($header)->toContain('HttpOnly');
        expect($header)->toContain('SameSite=Strict');
    });

    it('creates partitioned cookie with correct attributes', function () {
        $cookie = new Cookie(
            name: 'widget_session',
            value: 'widget123',
            secure: true,
            sameSite: SameSite::None,
            partitioned: true
        );

        expect($cookie->partitioned)->toBeTrue();
        expect($cookie->secure)->toBeTrue();
        expect($cookie->sameSite)->toBe(SameSite::None);

        $header = $cookie->toHeaderString();
        expect($header)->toContain('Partitioned');
        expect($header)->toContain('Secure');
        expect($header)->toContain('SameSite=None');
    });

    it('throws exception for partitioned cookie without Secure', function () {
        expect(fn () => new Cookie(
            name: 'test',
            value: 'value',
            secure: false,  // Invalid!
            sameSite: SameSite::None,
            partitioned: true
        ))->toThrow(InvalidArgumentException::class, 'Partitioned cookies require Secure=true and SameSite=None');
    });

    it('throws exception for partitioned cookie without SameSite=None', function () {
        expect(fn () => new Cookie(
            name: 'test',
            value: 'value',
            secure: true,
            sameSite: SameSite::Lax,  // Invalid!
            partitioned: true
        ))->toThrow(InvalidArgumentException::class, 'Partitioned cookies require Secure=true and SameSite=None');
    });

    it('throws exception for partitioned cookie with SameSite=Strict', function () {
        expect(fn () => new Cookie(
            name: 'test',
            value: 'value',
            secure: true,
            sameSite: SameSite::Strict,  // Invalid!
            partitioned: true
        ))->toThrow(InvalidArgumentException::class);
    });

    it('allows non-partitioned cookie with any SameSite', function () {
        $cookieLax = new Cookie(
            name: 'test1',
            value: 'value1',
            sameSite: SameSite::Lax,
            partitioned: false
        );

        $cookieStrict = new Cookie(
            name: 'test2',
            value: 'value2',
            sameSite: SameSite::Strict,
            partitioned: false
        );

        expect($cookieLax->sameSite)->toBe(SameSite::Lax);
        expect($cookieStrict->sameSite)->toBe(SameSite::Strict);
    });

    it('encodes cookie name and value in header', function () {
        $cookie = new Cookie(
            name: 'user_email',
            value: 'test@example.com'
        );

        $header = $cookie->toHeaderString();

        expect($header)->toContain(urlencode('user_email'));
        expect($header)->toContain(urlencode('test@example.com'));
    });

    it('converts to string using toHeaderString', function () {
        $cookie = new Cookie(
            name: 'test',
            value: 'value'
        );

        expect((string) $cookie)->toBe($cookie->toHeaderString());
    });

    it('does not include Partitioned for non-partitioned cookies', function () {
        $cookie = new Cookie(
            name: 'standard',
            value: 'cookie',
            partitioned: false
        );

        $header = $cookie->toHeaderString();
        expect($header)->not->toContain('Partitioned');
    });
});
