/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

const RequestContextAdaptor = require('../src/utils/RequestContextAdaptor');
const PlainDataObject = require('../src/model/PlainDataObject');

/**
 * Unit tests for RequestContextAdaptor
 *
 * Tests cover:
 * - Basic extraction functionality
 * - Various Node.js framework patterns (Express, Fastify, Koa, native http, etc.)
 * - Edge cases and error handling
 * - Proxy and load balancer scenarios
 */
describe('RequestContextAdaptor', () => {
    // =========================================================================
    // Basic Functionality Tests
    // =========================================================================

    describe('Basic Functionality', () => {
        test('extract returns PlainDataObject', () => {
            const result = RequestContextAdaptor.extract(null);
            expect(result).toBeInstanceOf(PlainDataObject);
        });

        test('extract with no arguments returns default values', () => {
            const result = RequestContextAdaptor.extract();

            expect(result.host).toBe('');
            expect(result.query_params).toEqual({});
            expect(result.cookies).toEqual({});
            expect(result.referer).toBeNull();
            expect(result.x_forwarded_for).toBeNull();
            expect(result.remote_address).toBeNull();
        });

        test('extract with null request returns default values', () => {
            const result = RequestContextAdaptor.extract(null);

            expect(result.host).toBe('');
            expect(result.query_params).toEqual({});
            expect(result.cookies).toEqual({});
            expect(result.referer).toBeNull();
            expect(result.x_forwarded_for).toBeNull();
            expect(result.remote_address).toBeNull();
        });

        test('extract with undefined request returns default values', () => {
            const result = RequestContextAdaptor.extract(undefined);

            expect(result.host).toBe('');
            expect(result.query_params).toEqual({});
            expect(result.cookies).toEqual({});
            expect(result.referer).toBeNull();
            expect(result.x_forwarded_for).toBeNull();
            expect(result.remote_address).toBeNull();
        });

        test('extract with empty object returns default values', () => {
            const result = RequestContextAdaptor.extract({});

            expect(result.host).toBe('');
            expect(result.query_params).toEqual({});
            expect(result.cookies).toEqual({});
            expect(result.referer).toBeNull();
            expect(result.x_forwarded_for).toBeNull();
            expect(result.remote_address).toBeNull();
        });
    });

    // =========================================================================
    // Header Extraction Tests
    // =========================================================================

    describe('Header Extraction', () => {
        test('extract host from headers', () => {
            const req = {
                headers: { host: 'www.example.com' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.host).toBe('www.example.com');
        });

        test('extract host with port', () => {
            const req = {
                headers: { host: 'localhost:8080' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.host).toBe('localhost:8080');
        });

        test('extract referer from headers', () => {
            const req = {
                headers: { referer: 'https://google.com/search?q=test' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.referer).toBe('https://google.com/search?q=test');
        });

        test('extract referrer (alternative spelling) from headers', () => {
            const req = {
                headers: { referrer: 'https://google.com/search?q=test' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.referer).toBe('https://google.com/search?q=test');
        });

        test('extract x-forwarded-for from headers', () => {
            const req = {
                headers: { 'x-forwarded-for': '203.0.113.195, 70.41.3.18, 150.172.238.178' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.x_forwarded_for).toBe('203.0.113.195, 70.41.3.18, 150.172.238.178');
        });

        test('extract remote address from socket', () => {
            const req = {
                headers: {},
                socket: { remoteAddress: '192.168.1.100' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.remote_address).toBe('192.168.1.100');
        });

        test('extract all headers', () => {
            const req = {
                headers: {
                    host: 'api.example.com',
                    referer: 'https://referrer.com',
                    'x-forwarded-for': '8.8.8.8',
                },
                socket: { remoteAddress: '10.0.0.1' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('api.example.com');
            expect(result.referer).toBe('https://referrer.com');
            expect(result.x_forwarded_for).toBe('8.8.8.8');
            expect(result.remote_address).toBe('10.0.0.1');
        });
    });

    // =========================================================================
    // Query Parameter Tests
    // =========================================================================

    describe('Query Parameter Extraction', () => {
        test('extract query params from framework-parsed query object', () => {
            const req = {
                headers: { host: 'example.com' },
                query: { foo: 'bar', baz: 'qux' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.query_params).toEqual({ foo: 'bar', baz: 'qux' });
        });

        test('extract query params from URL when query object not available', () => {
            const req = {
                headers: { host: 'example.com' },
                url: '/path?param1=value1&param2=value2',
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.query_params).toEqual({ param1: 'value1', param2: 'value2' });
        });

        test('query object takes precedence over URL parsing', () => {
            const req = {
                headers: { host: 'example.com' },
                query: { from_query: 'true' },
                url: '/path?from_url=true',
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.query_params).toEqual({ from_query: 'true' });
        });

        test('extract query params with URL-encoded values', () => {
            const req = {
                headers: { host: 'example.com' },
                url: '/path?name=John%20Doe&email=test%40example.com',
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.query_params.name).toBe('John Doe');
            expect(result.query_params.email).toBe('test@example.com');
        });

        test('extract query params with empty URL', () => {
            const req = {
                headers: { host: 'example.com' },
                url: '/path',
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.query_params).toEqual({});
        });

        test('handle URL with only question mark', () => {
            const req = {
                headers: { host: 'example.com' },
                url: '/path?',
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.query_params).toEqual({});
        });

        test('req.query as array is rejected, falls back to URL parse', () => {
            // typeof [] === 'object' in JS, so without the !Array.isArray
            // guard the adaptor would silently accept an array as the query
            // bag and break downstream `queries[paramName]` lookups.
            const req = {
                headers: { host: 'example.com' },
                query: ['not', 'a', 'query', 'object'],
                url: '/path?fallback=true',
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.query_params).toEqual({ fallback: 'true' });
        });
    });

    // =========================================================================
    // Cookie Extraction Tests
    // =========================================================================

    describe('Cookie Extraction', () => {
        test('extract cookies from framework-parsed cookies object', () => {
            const req = {
                headers: {},
                cookies: { session_id: 'abc123', user_pref: 'dark_mode' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.cookies).toEqual({ session_id: 'abc123', user_pref: 'dark_mode' });
        });

        test('extract cookies from cookie header when cookies object not available', () => {
            const req = {
                headers: { cookie: 'cookie1=value1; cookie2=value2' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.cookies).toEqual({ cookie1: 'value1', cookie2: 'value2' });
        });

        test('cookies object takes precedence over cookie header', () => {
            const req = {
                headers: { cookie: 'from_header=true' },
                cookies: { from_object: 'true' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.cookies).toEqual({ from_object: 'true' });
        });

        test('extract cookies with URL-encoded values', () => {
            const req = {
                headers: { cookie: 'encoded=hello%20world; special=a%3Db%26c%3Dd' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.cookies.encoded).toBe('hello world');
            expect(result.cookies.special).toBe('a=b&c=d');
        });

        test('extract cookies with whitespace', () => {
            const req = {
                headers: { cookie: '  cookie1=value1  ;   cookie2=value2  ; cookie3=value3' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.cookies).toHaveProperty('cookie1');
            expect(result.cookies).toHaveProperty('cookie2');
            expect(result.cookies).toHaveProperty('cookie3');
        });

        test('extract cookies with malformed pairs (skip invalid)', () => {
            const req = {
                headers: { cookie: 'valid=value; invalid_no_equals; another=test' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.cookies.valid).toBe('value');
            expect(result.cookies.another).toBe('test');
            expect(result.cookies).not.toHaveProperty('invalid_no_equals');
        });

        test('extract cookies with empty value', () => {
            const req = {
                headers: { cookie: 'empty=; normal=value' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.cookies.empty).toBe('');
            expect(result.cookies.normal).toBe('value');
        });

        test('handle empty cookie header', () => {
            const req = {
                headers: { cookie: '' },
            };
            const result = RequestContextAdaptor.extract(req);
            expect(result.cookies).toEqual({});
        });
    });

    // =========================================================================
    // Express.js Framework Tests
    // =========================================================================

    describe('Express.js Framework', () => {
        test('typical Express request', () => {
            const req = {
                headers: {
                    host: 'express-app.com',
                    referer: 'https://google.com',
                    'x-forwarded-for': '203.0.113.50',
                },
                socket: { remoteAddress: '127.0.0.1' },
                query: { page: '1', sort: 'name' },
                cookies: { express_session: 's%3Axyz123.signature' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('express-app.com');
            expect(result.query_params).toEqual({ page: '1', sort: 'name' });
            expect(result.cookies).toEqual({ express_session: 's%3Axyz123.signature' });
            expect(result.referer).toBe('https://google.com');
            expect(result.x_forwarded_for).toBe('203.0.113.50');
            expect(result.remote_address).toBe('127.0.0.1');
        });

        test('Express request with cookie-parser middleware', () => {
            const req = {
                headers: {
                    host: 'express-app.com',
                    cookie: 'raw_cookie=should_be_ignored',
                },
                cookies: { parsed_cookie: 'parsed_value' },
            };

            const result = RequestContextAdaptor.extract(req);
            expect(result.cookies).toEqual({ parsed_cookie: 'parsed_value' });
        });

        test('Express request without middleware (raw headers)', () => {
            const req = {
                headers: {
                    host: 'express-app.com',
                    cookie: 'session=abc123',
                },
                url: '/api/users?id=42',
            };

            const result = RequestContextAdaptor.extract(req);
            expect(result.query_params).toEqual({ id: '42' });
            expect(result.cookies).toEqual({ session: 'abc123' });
        });
    });

    // =========================================================================
    // Fastify Framework Tests
    // =========================================================================

    describe('Fastify Framework', () => {
        test('typical Fastify request with raw wrapper', () => {
            // Fastify wraps the native request in .raw
            const nativeReq = {
                headers: {
                    host: 'fastify-app.com',
                    referer: 'https://example.com',
                    'x-forwarded-for': '8.8.8.8',
                },
                socket: { remoteAddress: '127.0.0.1' },
                url: '/api/data?key=value',
            };

            const fastifyReq = {
                raw: nativeReq,
                query: { key: 'value' },
                cookies: { fastify_session: 'session123' },
            };

            const result = RequestContextAdaptor.extract(fastifyReq);

            expect(result.host).toBe('fastify-app.com');
            expect(result.query_params).toEqual({ key: 'value' });
            expect(result.cookies).toEqual({ fastify_session: 'session123' });
            expect(result.referer).toBe('https://example.com');
            expect(result.x_forwarded_for).toBe('8.8.8.8');
            expect(result.remote_address).toBe('127.0.0.1');
        });

        test('Fastify request without cookie plugin', () => {
            const nativeReq = {
                headers: {
                    host: 'fastify-app.com',
                    cookie: 'raw_cookie=value',
                },
                url: '/path',
            };

            const fastifyReq = {
                raw: nativeReq,
            };

            const result = RequestContextAdaptor.extract(fastifyReq);
            expect(result.cookies).toEqual({ raw_cookie: 'value' });
        });
    });

    // =========================================================================
    // Koa Framework Tests
    // =========================================================================

    describe('Koa Framework', () => {
        test('typical Koa request with req wrapper', () => {
            // Koa wraps the native request in .req
            const nativeReq = {
                headers: {
                    host: 'koa-app.com',
                    referer: 'https://koa.io',
                    'x-forwarded-for': '1.2.3.4',
                },
                socket: { remoteAddress: '10.0.0.1' },
                url: '/api?action=list',
            };

            const koaCtx = {
                req: nativeReq,
                query: { action: 'list' },
                cookies: { koa_session: 'sess_koa123' },
            };

            const result = RequestContextAdaptor.extract(koaCtx);

            expect(result.host).toBe('koa-app.com');
            expect(result.query_params).toEqual({ action: 'list' });
            expect(result.cookies).toEqual({ koa_session: 'sess_koa123' });
            expect(result.referer).toBe('https://koa.io');
            expect(result.x_forwarded_for).toBe('1.2.3.4');
            expect(result.remote_address).toBe('10.0.0.1');
        });
    });

    // =========================================================================
    // Native Node.js http.IncomingMessage Tests
    // =========================================================================

    describe('Native Node.js http.IncomingMessage', () => {
        test('native http request object', () => {
            const req = {
                headers: {
                    host: 'native-app.com',
                    referer: 'https://nodejs.org',
                    'x-forwarded-for': '5.6.7.8',
                    cookie: 'native_cookie=native_value',
                },
                socket: { remoteAddress: '172.16.0.1' },
                url: '/api/native?param=test',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('native-app.com');
            expect(result.query_params).toEqual({ param: 'test' });
            expect(result.cookies).toEqual({ native_cookie: 'native_value' });
            expect(result.referer).toBe('https://nodejs.org');
            expect(result.x_forwarded_for).toBe('5.6.7.8');
            expect(result.remote_address).toBe('172.16.0.1');
        });

        test('http2 request object', () => {
            const req = {
                headers: {
                    ':authority': 'http2-app.com',
                    host: 'http2-app.com',
                    referer: 'https://http2.github.io',
                },
                socket: { remoteAddress: '::1' },
                url: '/h2/path',
            };

            const result = RequestContextAdaptor.extract(req);
            expect(result.host).toBe('http2-app.com');
            expect(result.remote_address).toBe('::1');
        });

        test('http2 :authority used as host fallback when host header absent', () => {
            // Pure HTTP/2 requests may omit the legacy `host` header and
            // only carry `:authority`. The adaptor should fall back to it.
            const req = {
                headers: { ':authority': 'http2-pure.example.com' },
                socket: { remoteAddress: '::1' },
            };

            const result = RequestContextAdaptor.extract(req);
            expect(result.host).toBe('http2-pure.example.com');
        });

        test('host header takes precedence over :authority', () => {
            const req = {
                headers: {
                    host: 'host.example.com',
                    ':authority': 'authority.example.com',
                },
            };

            const result = RequestContextAdaptor.extract(req);
            expect(result.host).toBe('host.example.com');
        });
    });

    // =========================================================================
    // Hapi Framework Tests
    // =========================================================================

    describe('Hapi Framework', () => {
        test('typical Hapi request', () => {
            // Hapi wraps native request in .raw property
            // Note: The adaptor only drills one level deep (.raw or .req)
            const nativeReq = {
                headers: {
                    host: 'hapi-app.com',
                    referer: 'https://hapi.dev',
                    'x-forwarded-for': '9.9.9.9',
                    cookie: 'hapi_session=hapi123',
                },
                socket: { remoteAddress: '192.168.0.1' },
                url: '/hapi/endpoint',
            };

            const hapiReq = {
                raw: nativeReq,
                query: { hapi_param: 'value' },
            };

            const result = RequestContextAdaptor.extract(hapiReq);

            expect(result.host).toBe('hapi-app.com');
            expect(result.query_params).toEqual({ hapi_param: 'value' });
            expect(result.referer).toBe('https://hapi.dev');
            expect(result.x_forwarded_for).toBe('9.9.9.9');
            expect(result.remote_address).toBe('192.168.0.1');
        });
    });

    // =========================================================================
    // Next.js Framework Tests
    // =========================================================================

    describe('Next.js Framework', () => {
        test('Next.js API route request', () => {
            const req = {
                headers: {
                    host: 'nextjs-app.vercel.app',
                    referer: 'https://nextjs.org',
                    'x-forwarded-for': '203.0.113.100',
                },
                socket: { remoteAddress: '10.0.0.1' },
                query: { slug: 'hello-world' },
                cookies: { next_session: 'next123' },
                url: '/api/posts?slug=hello-world',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('nextjs-app.vercel.app');
            expect(result.query_params).toEqual({ slug: 'hello-world' });
            expect(result.cookies).toEqual({ next_session: 'next123' });
            expect(result.referer).toBe('https://nextjs.org');
        });

        test('Next.js middleware request (Edge runtime)', () => {
            const req = {
                headers: {
                    host: 'edge.vercel.app',
                    'x-forwarded-for': '100.100.100.100',
                },
                url: '/api/edge?test=true',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('edge.vercel.app');
            expect(result.x_forwarded_for).toBe('100.100.100.100');
            expect(result.query_params).toEqual({ test: 'true' });
        });
    });

    // =========================================================================
    // NestJS Framework Tests
    // =========================================================================

    describe('NestJS Framework', () => {
        test('NestJS request (Express adapter)', () => {
            // NestJS with Express adapter behaves like Express
            const req = {
                headers: {
                    host: 'nestjs-app.com',
                    referer: 'https://nestjs.com',
                    'x-forwarded-for': '1.1.1.1',
                },
                socket: { remoteAddress: '127.0.0.1' },
                query: { nestParam: 'value' },
                cookies: { nest_session: 'nest123' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('nestjs-app.com');
            expect(result.query_params).toEqual({ nestParam: 'value' });
            expect(result.cookies).toEqual({ nest_session: 'nest123' });
        });

        test('NestJS request (Fastify adapter)', () => {
            const nativeReq = {
                headers: {
                    host: 'nestjs-fastify.com',
                    cookie: 'nest_fastify=value',
                },
                socket: { remoteAddress: '127.0.0.1' },
                url: '/api?fast=true',
            };

            const req = {
                raw: nativeReq,
                query: { fast: 'true' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('nestjs-fastify.com');
            expect(result.query_params).toEqual({ fast: 'true' });
            expect(result.cookies).toEqual({ nest_fastify: 'value' });
        });
    });

    // =========================================================================
    // Proxy and Load Balancer Tests
    // =========================================================================

    describe('Proxy and Load Balancer Scenarios', () => {
        test('behind Nginx reverse proxy', () => {
            const req = {
                headers: {
                    host: 'api.production.com',
                    'x-forwarded-for': '203.0.113.195, 70.41.3.18',
                    'x-real-ip': '203.0.113.195',
                },
                socket: { remoteAddress: '10.0.0.1' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('api.production.com');
            expect(result.x_forwarded_for).toBe('203.0.113.195, 70.41.3.18');
            expect(result.remote_address).toBe('10.0.0.1');
        });

        test('behind AWS Load Balancer', () => {
            const req = {
                headers: {
                    host: 'app.example.com',
                    'x-forwarded-for': '54.239.28.85',
                    'x-forwarded-proto': 'https',
                    'x-forwarded-port': '443',
                },
                socket: { remoteAddress: '172.31.0.1' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.x_forwarded_for).toBe('54.239.28.85');
            expect(result.remote_address).toBe('172.31.0.1');
        });

        test('behind Cloudflare', () => {
            const req = {
                headers: {
                    host: 'protected.example.com',
                    'cf-connecting-ip': '203.0.113.50',
                    'x-forwarded-for': '203.0.113.50, 172.64.0.1',
                },
                socket: { remoteAddress: '172.64.0.1' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.x_forwarded_for).toBe('203.0.113.50, 172.64.0.1');
        });

        test('multiple proxy chain', () => {
            const req = {
                headers: {
                    host: 'api.example.com',
                    'x-forwarded-for': '203.0.113.50, 10.0.0.1, 172.31.0.1',
                },
                socket: { remoteAddress: '192.168.1.1' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.x_forwarded_for).toBe('203.0.113.50, 10.0.0.1, 172.31.0.1');
            expect(result.remote_address).toBe('192.168.1.1');
        });
    });

    // =========================================================================
    // IPv6 Tests
    // =========================================================================

    describe('IPv6 Support', () => {
        test('IPv6 remote address', () => {
            const req = {
                headers: { host: 'ipv6.example.com' },
                socket: { remoteAddress: '2001:0db8:85a3:0000:0000:8a2e:0370:7334' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.remote_address).toBe('2001:0db8:85a3:0000:0000:8a2e:0370:7334');
        });

        test('IPv6 in x-forwarded-for', () => {
            const req = {
                headers: {
                    host: 'example.com',
                    'x-forwarded-for': '2001:db8::1, 2001:db8::2',
                },
                socket: { remoteAddress: '::1' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.x_forwarded_for).toBe('2001:db8::1, 2001:db8::2');
            expect(result.remote_address).toBe('::1');
        });

        test('IPv6 loopback address', () => {
            const req = {
                headers: { host: 'localhost' },
                socket: { remoteAddress: '::1' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.remote_address).toBe('::1');
        });
    });

    // =========================================================================
    // Edge Cases and Error Handling
    // =========================================================================

    describe('Edge Cases and Error Handling', () => {
        test('null values in headers', () => {
            const req = {
                headers: {
                    host: null,
                    referer: null,
                    'x-forwarded-for': null,
                },
                socket: { remoteAddress: null },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('');
            expect(result.referer).toBeNull();
            expect(result.x_forwarded_for).toBeNull();
        });

        test('empty strings in headers', () => {
            const req = {
                headers: {
                    host: '',
                    referer: '',
                    'x-forwarded-for': '',
                },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('');
        });

        test('very long hostname', () => {
            const longHost = 'a'.repeat(255) + '.example.com';
            const req = {
                headers: { host: longHost },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe(longHost);
        });

        test('very long query string', () => {
            const longValue = 'x'.repeat(10000);
            const req = {
                headers: { host: 'example.com' },
                url: `/path?long_param=${longValue}`,
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.query_params.long_param).toBe(longValue);
        });

        test('many cookies', () => {
            const cookieParts = [];
            for (let i = 0; i < 50; i++) {
                cookieParts.push(`cookie${i}=value${i}`);
            }
            const req = {
                headers: { cookie: cookieParts.join('; ') },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(Object.keys(result.cookies).length).toBe(50);
            expect(result.cookies.cookie0).toBe('value0');
            expect(result.cookies.cookie49).toBe('value49');
        });

        test('special characters in referer', () => {
            const req = {
                headers: {
                    referer: 'https://example.com/path?query=hello%20world&special=<script>',
                },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.referer).toBe(
                'https://example.com/path?query=hello%20world&special=<script>'
            );
        });

        test('unicode in query params', () => {
            const req = {
                headers: { host: 'example.com' },
                query: { name: '日本語', emoji: '🚀' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.query_params.name).toBe('日本語');
            expect(result.query_params.emoji).toBe('🚀');
        });

        test('unicode in cookies', () => {
            const req = {
                headers: {},
                cookies: { lang: 'العربية' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies.lang).toBe('العربية');
        });

        test('missing headers object', () => {
            const req = {
                url: '/path?param=value',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('');
        });

        test('request with only socket', () => {
            const req = {
                socket: { remoteAddress: '192.168.1.1' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.remote_address).toBe('192.168.1.1');
        });

        test('socket without remoteAddress', () => {
            const req = {
                headers: { host: 'example.com' },
                socket: {},
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.remote_address).toBeNull();
        });
    });

    // =========================================================================
    // Cookie Edge Cases
    // =========================================================================

    describe('Cookie Edge Cases', () => {
        test('cookie with equals sign in value', () => {
            const req = {
                headers: { cookie: 'base64=dGVzdD1pbj1kYXRh' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies.base64).toBe('dGVzdD1pbj1kYXRh');
        });

        test('cookie with multiple equals signs in value is preserved', () => {
            const req = {
                headers: { cookie: 'complex=a=b=c=d' },
            };

            const result = RequestContextAdaptor.extract(req);

            // strToMap now splits on the FIRST `=` only, so values containing
            // `=` (e.g. base64 padding) are preserved intact.
            expect(result.cookies.complex).toBe('a=b=c=d');
        });

        test('base64 padded cookie value is preserved (e.g. _fbc)', () => {
            const req = {
                headers: { cookie: '_fbc=fb.1.123.YWJjZA==; _fbp=fb.1.456.7890' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies._fbc).toBe('fb.1.123.YWJjZA==');
            expect(result.cookies._fbp).toBe('fb.1.456.7890');
        });

        test('cookie with literal plus is preserved', () => {
            // Cookies are not query strings: literal `+` (common in base64
            // / JWT values) must NOT be converted to space.
            // decodeURIComponent (unlike URLSearchParams) preserves `+`.
            const req = {
                headers: { cookie: 'token=abc+def==; jwt=eyJ+payload' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies.token).toBe('abc+def==');
            expect(result.cookies.jwt).toBe('eyJ+payload');
        });

        test('one malformed cookie does not drop other valid cookies', () => {
            // %E0 by itself is an incomplete UTF-8 escape and throws URIError
            // from decodeURIComponent. Per-pair isolation should skip only
            // the malformed pair instead of returning {}.
            const req = {
                headers: { cookie: 'valid=value; bad=%E0%A4; another=test' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies.valid).toBe('value');
            expect(result.cookies.another).toBe('test');
            expect(result.cookies.bad).toBeUndefined();
        });

        test('cookie with empty key (orphan = at start) is skipped', () => {
            const req = {
                headers: { cookie: '=orphan; valid=value' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies['']).toBeUndefined();
            expect(result.cookies.valid).toBe('value');
        });

        test('empty cookie header', () => {
            const req = {
                headers: { cookie: '' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies).toEqual({});
        });

        test('cookie with only semicolons', () => {
            const req = {
                headers: { cookie: ';;;' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies).toEqual({});
        });
    });

    // =========================================================================
    // Consistency Tests
    // =========================================================================

    describe('Consistency Tests', () => {
        test('multiple calls produce same result', () => {
            const req = {
                headers: {
                    host: 'consistent.example.com',
                    referer: 'https://referrer.com',
                },
                socket: { remoteAddress: '8.8.8.8' },
            };

            const result1 = RequestContextAdaptor.extract(req);
            const result2 = RequestContextAdaptor.extract(req);

            expect(result1.host).toBe(result2.host);
            expect(result1.referer).toBe(result2.referer);
            expect(result1.remote_address).toBe(result2.remote_address);
        });

        test('does not modify input object', () => {
            const req = {
                headers: {
                    host: 'example.com',
                    referer: 'https://referrer.com',
                },
            };
            const originalReq = JSON.parse(JSON.stringify(req));

            RequestContextAdaptor.extract(req);

            expect(req).toEqual(originalReq);
        });
    });

    // =========================================================================
    // Facebook/Meta Specific Cookie Tests
    // =========================================================================

    describe('Facebook/Meta Specific Cookies', () => {
        test('FBI cookie extraction', () => {
            const req = {
                headers: {},
                cookies: { _fbi: '8.8.8.8.en' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies._fbi).toBe('8.8.8.8.en');
        });

        test('FBP cookie extraction', () => {
            const req = {
                headers: {},
                cookies: { _fbp: 'fb.1.1234567890123.1234567890' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies._fbp).toBe('fb.1.1234567890123.1234567890');
        });

        test('FBC cookie extraction', () => {
            const req = {
                headers: {},
                cookies: { _fbc: 'fb.1.1234567890123.AbCdEfGhIjKlMnOpQrStUvWxYz' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.cookies._fbc).toBe('fb.1.1234567890123.AbCdEfGhIjKlMnOpQrStUvWxYz');
        });

        test('fbclid in query params', () => {
            const req = {
                headers: { host: 'example.com' },
                query: { fbclid: 'IwAR3xYz_test_fbclid_value' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.query_params.fbclid).toBe('IwAR3xYz_test_fbclid_value');
        });
    });

    // =========================================================================
    // Security-Related Tests
    // =========================================================================

    describe('Security-Related Tests', () => {
        test('potentially malicious host header', () => {
            const req = {
                headers: {
                    host: 'evil.com\\r\\nX-Injected: header',
                },
            };

            const result = RequestContextAdaptor.extract(req);

            // The class should extract as-is without modification
            // Security validation should be done by the consumer
            expect(result.host).toBe('evil.com\\r\\nX-Injected: header');
        });

        test('script tags in query params', () => {
            const req = {
                headers: { host: 'example.com' },
                query: { xss: '<script>alert("xss")</script>' },
            };

            const result = RequestContextAdaptor.extract(req);

            // Raw extraction - no sanitization
            expect(result.query_params.xss).toBe('<script>alert("xss")</script>');
        });

        test('SQL injection in query params', () => {
            const req = {
                headers: { host: 'example.com' },
                query: { id: "1'; DROP TABLE users; --" },
            };

            const result = RequestContextAdaptor.extract(req);

            // Raw extraction - no sanitization
            expect(result.query_params.id).toBe("1'; DROP TABLE users; --");
        });
    });

    // =========================================================================
    // Real-World E-commerce Scenarios
    // =========================================================================

    describe('Real-World E-commerce Scenarios', () => {
        test('e-commerce checkout page', () => {
            const req = {
                headers: {
                    host: 'shop.example.com',
                    referer: 'https://shop.example.com/cart',
                    'x-forwarded-for': '203.0.113.50',
                },
                socket: { remoteAddress: '10.0.0.1' },
                query: { step: 'payment', cart_id: 'abc123' },
                cookies: {
                    session_id: 'sess_xyz789',
                    _fbp: 'fb.1.1234567890.987654321',
                    _fbc: 'fb.1.1234567890.IwAR123456',
                    cart: 'encoded_cart_data',
                },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('shop.example.com');
            expect(result.query_params.step).toBe('payment');
            expect(result.cookies._fbp).toBeDefined();
            expect(result.cookies._fbc).toBeDefined();
            expect(result.referer).toBe('https://shop.example.com/cart');
        });

        test('landing page with UTM params', () => {
            const req = {
                headers: {
                    host: 'landing.example.com',
                    referer: 'https://www.facebook.com/',
                },
                socket: { remoteAddress: '8.8.8.8' },
                query: {
                    utm_source: 'facebook',
                    utm_medium: 'cpc',
                    utm_campaign: 'spring_sale',
                    fbclid: 'IwAR3abc123',
                },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.query_params.utm_source).toBe('facebook');
            expect(result.query_params.fbclid).toBe('IwAR3abc123');
            expect(result.referer).toBe('https://www.facebook.com/');
        });
    });

    // =========================================================================
    // HTTPS/SSL Tests
    // =========================================================================

    describe('HTTPS/SSL Tests', () => {
        test('HTTPS request', () => {
            const req = {
                headers: {
                    host: 'secure.example.com',
                    'x-forwarded-proto': 'https',
                },
                socket: { remoteAddress: '192.168.1.1' },
                connection: { encrypted: true },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('secure.example.com');
        });
    });

    // =========================================================================
    // Performance Tests
    // =========================================================================

    describe('Performance Tests', () => {
        test('handle rapid successive calls', () => {
            const req = {
                headers: {
                    host: 'performance.example.com',
                    referer: 'https://test.com',
                },
                socket: { remoteAddress: '1.2.3.4' },
                query: { test: 'value' },
                cookies: { session: 'abc' },
            };

            for (let i = 0; i < 100; i++) {
                const result = RequestContextAdaptor.extract(req);
                expect(result.host).toBe('performance.example.com');
            }
        });
    });

    // =========================================================================
    // AWS Lambda / Serverless Tests
    // =========================================================================

    describe('Serverless Environment Tests', () => {
        test('AWS Lambda with API Gateway event', () => {
            // Simulating Lambda request via API Gateway proxy integration
            const req = {
                headers: {
                    host: 'api.example.com',
                    'x-forwarded-for': '203.0.113.100, 10.0.0.1',
                    'x-forwarded-proto': 'https',
                    'x-forwarded-port': '443',
                },
                socket: { remoteAddress: '127.0.0.1' },
                query: { action: 'process' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('api.example.com');
            expect(result.x_forwarded_for).toBe('203.0.113.100, 10.0.0.1');
            expect(result.query_params).toEqual({ action: 'process' });
        });

        test('Vercel serverless function', () => {
            const req = {
                headers: {
                    host: 'my-app.vercel.app',
                    'x-forwarded-for': '1.2.3.4',
                    'x-vercel-id': 'sfo1::iad1::abc123',
                },
                query: { slug: 'test' },
                cookies: { __session: 'vercel_session' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('my-app.vercel.app');
            expect(result.x_forwarded_for).toBe('1.2.3.4');
            expect(result.query_params.slug).toBe('test');
            expect(result.cookies.__session).toBe('vercel_session');
        });
    });

    // =========================================================================
    // Framework Wrapper Depth Tests
    // =========================================================================

    describe('Framework Wrapper Depth Tests', () => {
        test('single level wrapper (.req)', () => {
            const nativeReq = {
                headers: { host: 'single.example.com' },
                socket: { remoteAddress: '1.1.1.1' },
            };
            const wrappedReq = { req: nativeReq };

            const result = RequestContextAdaptor.extract(wrappedReq);

            expect(result.host).toBe('single.example.com');
            expect(result.remote_address).toBe('1.1.1.1');
        });

        test('single level wrapper (.raw)', () => {
            const nativeReq = {
                headers: { host: 'raw.example.com' },
                socket: { remoteAddress: '2.2.2.2' },
            };
            const wrappedReq = { raw: nativeReq };

            const result = RequestContextAdaptor.extract(wrappedReq);

            expect(result.host).toBe('raw.example.com');
            expect(result.remote_address).toBe('2.2.2.2');
        });

        test('prefer direct headers over wrapped', () => {
            // When the wrapper also has headers, it should use the unwrapped version
            const nativeReq = {
                headers: { host: 'native.example.com' },
            };
            const wrappedReq = {
                req: nativeReq,
                headers: { host: 'wrapper.example.com' },
            };

            const result = RequestContextAdaptor.extract(wrappedReq);

            // Based on the implementation: const r = req.req || req.raw || req;
            // It drills down to the native request
            expect(result.host).toBe('native.example.com');
        });
    });

    // =========================================================================
    // Error Recovery Tests
    // =========================================================================

    describe('Error Recovery Tests', () => {
        test('malformed URL should not throw', () => {
            const req = {
                headers: { host: 'example.com' },
                url: '//invalid-url',
            };

            expect(() => {
                RequestContextAdaptor.extract(req);
            }).not.toThrow();
        });

        test('null socket should be handled gracefully', () => {
            const req = {
                headers: { host: 'example.com' },
                socket: null,
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.remote_address).toBeNull();
        });

        test('circular reference in request should not cause issues', () => {
            const req = {
                headers: { host: 'example.com' },
            };
            // Don't add circular reference as it would cause issues with the actual function

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('example.com');
        });
    });

    // =========================================================================
    // Scheme Extraction Tests
    // =========================================================================

    describe('Scheme Extraction', () => {
        test('scheme is https when socket.encrypted is truthy', () => {
            const req = {
                headers: { host: 'example.com' },
                socket: { encrypted: true },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.scheme).toBe('https');
        });

        test('scheme is https when req.protocol is https', () => {
            const req = {
                headers: { host: 'example.com' },
                protocol: 'https',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.scheme).toBe('https');
        });

        test('scheme is http when neither socket.encrypted nor req.protocol present', () => {
            const req = {
                headers: { host: 'example.com' },
                socket: {},
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.scheme).toBe('http');
        });

        test('req.protocol takes precedence over socket.encrypted', () => {
            const req = {
                headers: { host: 'example.com' },
                protocol: 'http',
                socket: { encrypted: true },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.scheme).toBe('http');
        });

        test('scheme defaults to http when socket is missing', () => {
            const req = {
                headers: { host: 'example.com' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.scheme).toBe('http');
        });
    });

    // =========================================================================
    // Request URI Extraction Tests
    // =========================================================================

    describe('Request URI Extraction', () => {
        test('request_uri from req.originalUrl (Express)', () => {
            const req = {
                headers: { host: 'example.com' },
                originalUrl: '/app/page?id=42',
                url: '/page?id=42',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.request_uri).toBe('/app/page?id=42');
        });

        test('request_uri from request.url (native Node.js)', () => {
            const req = {
                headers: { host: 'example.com' },
                url: '/api/data?key=value',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.request_uri).toBe('/api/data?key=value');
        });

        test('request_uri with path and query string', () => {
            const req = {
                headers: { host: 'example.com' },
                url: '/search?q=test&page=2&lang=en',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.request_uri).toBe('/search?q=test&page=2&lang=en');
        });

        test('request_uri is null when no url present', () => {
            const req = {
                headers: { host: 'example.com' },
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.request_uri).toBeNull();
        });

        test('originalUrl takes precedence over url', () => {
            const req = {
                headers: { host: 'example.com' },
                originalUrl: '/mounted/path/resource',
                url: '/resource',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.request_uri).toBe('/mounted/path/resource');
        });
    });

    // =========================================================================
    // URL Extraction Does Not Affect Existing Fields
    // =========================================================================

    describe('URL extraction does not affect existing field extraction', () => {
        test('scheme and request_uri coexist with all other extracted fields', () => {
            const req = {
                headers: {
                    host: 'shop.example.com',
                    referer: 'https://google.com/search',
                    'x-forwarded-for': '203.0.113.50',
                    cookie: 'session=abc123',
                },
                socket: { remoteAddress: '10.0.0.1', encrypted: true },
                url: '/products?category=shoes',
                query: { category: 'shoes' },
                protocol: 'https',
                originalUrl: '/v2/products?category=shoes',
            };

            const result = RequestContextAdaptor.extract(req);

            expect(result.host).toBe('shop.example.com');
            expect(result.referer).toBe('https://google.com/search');
            expect(result.x_forwarded_for).toBe('203.0.113.50');
            expect(result.remote_address).toBe('10.0.0.1');
            expect(result.query_params).toEqual({ category: 'shoes' });
            expect(result.cookies).toEqual({ session: 'abc123' });
            expect(result.scheme).toBe('https');
            expect(result.request_uri).toBe('/v2/products?category=shoes');
        });
    });
});
