/**
 * Port for HTTP server creation.
 *
 * Abstracts platform-specific HTTP server APIs so domain code
 * doesn't depend on node:http directly.
 */
import WarpError from "../domain/errors/WarpError.js";
export class HttpBoundaryError extends WarpError {
    constructor(message, field) {
        super(message, 'E_HTTP_BOUNDARY_INVALID', { context: { field } });
    }
}
export class HttpRequest {
    /** HTTP method (GET, POST, etc.) */
    method;
    /** Request URL path + query string */
    url;
    /** Lowercased header map */
    headers;
    /** Raw body bytes (undefined for bodiless requests) */
    body;
    constructor(options) {
        assertRequestOptions(options);
        assertNonEmptyString(options.method, 'method');
        assertNonEmptyString(options.url, 'url');
        assertBody(options.body, 'body');
        this.method = options.method;
        this.url = options.url;
        this.headers = validatedHeaders(options.headers);
        this.body = options.body;
        Object.freeze(this);
    }
    static from(request) {
        return request instanceof HttpRequest ? request : new HttpRequest(request);
    }
}
export class HttpResponse {
    /** HTTP status code (defaults to 200) */
    status;
    /** Response headers */
    headers;
    /** Response body */
    body;
    constructor(options = {}) {
        assertResponseOptions(options);
        assertStatus(options.status);
        assertResponseBody(options.body);
        this.status = options.status;
        this.headers = options.headers === undefined ? undefined : validatedHeaders(options.headers);
        this.body = options.body;
        Object.freeze(this);
    }
    static from(response) {
        return response instanceof HttpResponse ? response : new HttpResponse(response);
    }
}
function assertRequestOptions(options) {
    if (options === null || typeof options !== 'object') {
        throw new HttpBoundaryError('HTTP request options must be an object', 'request');
    }
}
function assertResponseOptions(options) {
    if (options === null || typeof options !== 'object') {
        throw new HttpBoundaryError('HTTP response options must be an object', 'response');
    }
}
function assertNonEmptyString(value, field) {
    if (typeof value !== 'string' || value.length === 0) {
        throw new HttpBoundaryError(`HTTP ${field} must be a non-empty string`, field);
    }
}
function assertStatus(status) {
    if (status === undefined) {
        return;
    }
    if (!Number.isInteger(status) || status < 100 || status > 599) {
        throw new HttpBoundaryError('HTTP response status must be an integer from 100 through 599', 'status');
    }
}
function assertBody(body, field) {
    if (body !== undefined && !(body instanceof Uint8Array)) {
        throw new HttpBoundaryError(`HTTP ${field} must be Uint8Array or undefined`, field);
    }
}
function assertResponseBody(body) {
    if (body === undefined || body === null || typeof body === 'string' || body instanceof Uint8Array) {
        return;
    }
    throw new HttpBoundaryError('HTTP response body must be string, Uint8Array, null, or undefined', 'body');
}
function validatedHeaders(headers) {
    if (headers === null || typeof headers !== 'object') {
        throw new HttpBoundaryError('HTTP headers must be an object', 'headers');
    }
    const validated = {};
    for (const [key, value] of Object.entries(headers)) {
        assertNonEmptyString(key, 'headers');
        assertNonEmptyString(value, `headers.${key}`);
        validated[key.toLowerCase()] = value;
    }
    Object.freeze(validated);
    return validated;
}
/** Port for HTTP server creation. */
export default class HttpServerPort {
}
