/**
 * Request - HTTP Request wrapper
 * Wraps Node.js IncomingMessage with additional utilities
 */
import { FileUpload } from './FileUpload.js';
/**
 * Request - HTTP Request wrapper
 * Refactored to Functional Object pattern
 */
/**
 * Parse query string from URL
 */
const parseQuery = (urlStr) => {
    const query = {};
    const url = new URL(urlStr, 'http://localhost');
    url.searchParams.forEach((value, key) => {
        const existing = query[key];
        if (existing === undefined) {
            query[key] = value;
        }
        else if (Array.isArray(existing)) {
            existing.push(value);
        }
        else {
            query[key] = [existing, value];
        }
    });
    return query;
};
const isPlainObject = (value) => {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
};
const toBodyRecord = (value) => {
    return isPlainObject(value) ? value : {};
};
const createRequestState = (req) => {
    return {
        sessionId: req.headers['x-session-id'],
        user: undefined,
        params: {},
        body: null,
        bodyRecord: {},
        validated: {},
        _cachedData: undefined,
    };
};
const setBodyState = (state, newBody) => {
    state.body = newBody;
    state.bodyRecord = toBodyRecord(newBody);
    state._cachedData = undefined; // Clear cache when body changes
};
const createRequestProperties = (state, context) => {
    return {
        get sessionId() {
            return state.sessionId;
        },
        set sessionId(newSessionId) {
            state.sessionId = newSessionId;
        },
        get user() {
            return state.user;
        },
        set user(newUser) {
            state.user = newUser;
        },
        context,
        get params() {
            return state.params;
        },
        set params(newParams) {
            state.params = newParams;
        },
        get body() {
            return state.bodyRecord;
        },
        set body(newBody) {
            setBodyState(state, newBody);
        },
        get validated() {
            return state.validated;
        },
        set validated(v) {
            state.validated = v;
        },
    };
};
/**
 * Create HTTP method helpers
 */
function createHttpHelpers(req) {
    return {
        getMethod() {
            return req.method ?? 'GET';
        },
        getPath() {
            const url = req.url;
            return url === undefined ? '/' : url.split('?')[0];
        },
        getHeaders() {
            return req.headers;
        },
        get headers() {
            return req.headers;
        },
        getHeader(name) {
            return req.headers[name.toLowerCase()];
        },
    };
}
/**
 * Create parameter helpers
 */
function createParameterHelpers(state, query) {
    return {
        getParams() {
            return state.params;
        },
        getParam(key) {
            return state.params[key];
        },
        setParams(newParams) {
            state.params = newParams;
            state._cachedData = undefined; // Clear cache when params change
        },
        getQuery() {
            return query;
        },
        getQueryParam(key) {
            return query[key];
        },
    };
}
/**
 * Create body helpers
 */
function createBodyHelpers(state, req) {
    return {
        setBody(newBody) {
            setBodyState(state, newBody);
        },
        getBody() {
            return state.body;
        },
        isJson() {
            const contentType = req.headers['content-type'];
            return typeof contentType === 'string' && contentType.includes('application/json');
        },
    };
}
/**
 * Create file upload helpers
 */
function createFileHelpers(getCompleteRequest) {
    return {
        file(fieldName, options) {
            const handler = FileUpload.createHandler(getCompleteRequest());
            return handler.file(fieldName, options);
        },
        files(fieldName, options) {
            const handler = FileUpload.createHandler(getCompleteRequest());
            return handler.files(fieldName, options);
        },
        hasFile(fieldName) {
            const handler = FileUpload.createHandler(getCompleteRequest());
            return handler.hasFile(fieldName);
        },
        fileUpload() {
            return FileUpload.createHandler(getCompleteRequest());
        },
    };
}
/**
 * Create unified data helpers
 */
function createDataHelpers(state, query) {
    return {
        data() {
            // Precedence: Body > Path Params > Query Params
            state._cachedData ??= {
                ...query,
                ...state.params,
                ...state.bodyRecord,
            };
            return state._cachedData;
        },
        get(key, defaultValue) {
            const data = this.data();
            return data[key] ?? defaultValue;
        },
    };
}
const createRequestMethods = (req, query, state, context) => {
    return {
        ...createHttpHelpers(req),
        ...createParameterHelpers(state, query),
        ...createBodyHelpers(state, req),
        ...createFileHelpers(() => {
            // Create a complete request object for file handlers
            const completeRequest = {
                ...createHttpHelpers(req),
                ...createParameterHelpers(state, query),
                ...createBodyHelpers(state, req),
                ...createDataHelpers(state, query),
                getRaw: () => req,
                sessionId: state.sessionId,
                user: state.user,
                params: state.params,
                body: state.body,
                validated: state.validated,
                context,
            };
            return completeRequest;
        }),
        ...createDataHelpers(state, query),
        getRaw() {
            return req;
        },
    };
};
const createRequestApi = (req, query, context, state) => {
    return {
        ...createRequestProperties(state, context),
        ...createRequestMethods(req, query, state, context),
    };
};
export const Request = Object.freeze({
    /**
     * Create a new request instance
     */
    create(req) {
        const query = parseQuery(req.url ?? '/');
        const context = {};
        const state = createRequestState(req);
        return createRequestApi(req, query, context, state);
    },
});
export default Request;
