/**
 * HTTP Request Helper for Tests
 *
 * Provides utilities for making HTTP requests in tests.
 */

import { Request, Response } from 'express';
import { MockRequest, MockResponse } from 'node-mocks-http';

/**
 * Create a mock Express request
 */
export function createMockRequest(overrides: Partial<Request> = {}): Request {
	return {
		method: 'GET',
		url: '/test',
		headers: {
			'Content-Type': 'application/json',
		} as any,
		query: {},
		params: {},
		body: {},
		user: null,
		...overrides,
	} as Request;
}

/**
 * Create a mock Express response
 */
export function createMockResponse(overrides: Partial<MockResponse<Response>> = {}): MockResponse<Response> {
	const { createResponse } = require('node-mocks-http');

	return createResponse({
		eventEmitter: require('events').EventEmitter,
		...overrides,
	});
}

/**
 * Create mock request with JSON body
 */
export function createMockJsonRequest<T = any>(body: T, overrides: Partial<Request> = {}): any {
	return createMockRequest({
		method: 'POST',
		headers: {
			'Content-Type': 'application/json',
		} as any,
		body,
		...overrides,
	});
}

/**
 * Create mock authenticated request
 */
export function createMockAuthenticatedRequest(
	userId: string = '550e8400-e29b-41d4-a716-446655440000',
	email: string = 'test@example.com',
	roles: string[] = ['user'],
	overrides: Partial<Request> = {},
): Request {
	return createMockRequest({
		user: {
			sub: userId,
			id: userId,
			email: 'test@example.com',
			roles: [],
			aud: 'api-users',
			iss: 'backend-template',
			iat: Math.floor(Date.now() / 1000),
			exp: Math.floor(Date.now() / 1000) + 3600,
		},
		...overrides,
	});
}

/**
 * Wait for response to complete
 */
export function waitForResponse(response: MockResponse<Response>): Promise<void> {
	return new Promise((resolve, reject) => {
		response.on('end', () => {
			resolve();
		});

		response.on('error', (err: Error) => {
			reject(err);
		});

		// Timeout after 5 seconds
		setTimeout(() => {
			reject(new Error('Response timeout'));
		}, 5000);
	});
}

/**
 * Parse JSON response body
 */
export function parseJsonResponse<T = any>(response: MockResponse<Response>): T {
	const data = response._getData();

	if (typeof data === 'string') {
		return JSON.parse(data);
	}

	if (Buffer.isBuffer(data)) {
		return JSON.parse(data.toString());
	}

	return data;
}

/**
 * Get cookies from response
 */
export function getResponseCookies(
	response: MockResponse<Response>,
): Array<{ name: string; value: string; options?: any }> {
	const cookies: Array<{ name: string; value: string; options?: any }> = [];
	const cookieHeaders = (response.getHeader('Set-Cookie') as string[]) || [];

	for (const cookieHeader of cookieHeaders) {
		const parsedCookies = parseCookies(cookieHeader);
		cookies.push(...parsedCookies);
	}

	return cookies;
}

export function parseCookies(cookieHeader: string): Array<{ name: string; value: string; options?: any }> {
	const cookies: Array<{ name: string; value: string; options?: any }> = [];

	if (!cookieHeader) {
		return cookies;
	}

	const cookieParts = cookieHeader.split(';').map((part) => part.trim());

	for (const part of cookieParts) {
		if (part.includes('=')) {
			const mainPart = part.split(';')[0];
			if (!mainPart) continue;

			const [name, value] = mainPart.trim().split('=');
			let options: any = {};

			// Parse options after the main cookie
			const optionParts = part.split(';').slice(1);
			for (const optionPart of optionParts) {
				const trimmed = optionPart.trim();
				if (trimmed.includes('=')) {
					const [key, val] = trimmed.split('=');
					if (key && val) {
						if (key === 'maxAge' || key === 'expires') {
							options[key] = parseInt(val);
						} else {
							options[key] = val;
						}
					}
				} else if (trimmed) {
					options[trimmed] = true;
				}
			}

			if (name && value) {
				cookies.push({ name, value, options });
			}
		}
	}

	return cookies;
}
