import { IncomingHttpHeaders } from 'node:http';

type NonEmptyArray<T> = [T, ...T[]];
/** Minimal request interface — any object with headers and socket (Express v4, v5, etc.). */
interface IpRequest {
    ip?: string;
    headers: IncomingHttpHeaders;
    socket?: {
        remoteAddress?: string;
    };
    clientIp?: string;
    clientIps?: NonEmptyArray<string>;
}
/**
 * Extracts the client's IP address from an incoming Express request.
 *
 * This function works both as a standalone utility and as Express middleware.
 * It attempts to detect the IP by inspecting common proxy-related headers
 * such as `forwarded` (RFC 7239), `x-forwarded-for`, `x-real-ip`, and others. If no valid IP is found
 * in the headers, it falls back to `req.socket.remoteAddress`.
 * Header fallback is skipped when `req.socket.remoteAddress` is a public address,
 * reducing spoofing risk for direct internet-facing connections.
 *
 * When used as middleware, it populates:
 * - `req.clientIp`: The first valid IP address found.
 * - `req.clientIps`: A non-empty array of all valid IPs found.
 *
 * **Security note — trust boundary:** This function checks `req.ip` first (which
 * respects Express's `trust proxy` setting). When `req.ip` is falsy, it
 * reads forwarding headers **only** if the socket peer (`req.socket.remoteAddress`)
 * is a recognized private/proxy address. When the socket identity is absent or
 * public, headers are **not** trusted and the function falls back to
 * `req.socket.remoteAddress` directly. In production behind a reverse proxy,
 * configure Express's `trust proxy` so `req.ip` is populated correctly and
 * treated as the primary source of truth.
 *
 * @param req - The Express request object.
 * @param res - (Optional) The Express response object. Included to support middleware signature.
 * @param next - (Optional) The next function in the Express middleware chain.
 *
 * @returns The first detected client IP address as a string, or `undefined` if none is found.
 *
 * @throws Will throw an error if the `req` argument is not defined.
 *
 * @example
 * // Standalone usage:
 * app.get('/standalone-ip', (req, res) => {
 *   const ip = getClientIp(req);
 *   res.status(200).json({ ip });
 * });
 *
 * @example
 * // Middleware usage:
 * app.use(getClientIp);
 * app.get('/middleware-ip', (req, res) => {
 *   res.status(200).json({ ip: req.clientIp, ips: req.clientIps });
 * });
 */
declare function getClientIp(req: IpRequest, res?: unknown, next?: (...args: any[]) => void): string | undefined;
declare global {
    namespace Express {
        interface Request {
            /** The first IP address extracted from the request. */
            clientIp?: string;
            /** All IP addresses extracted from the request. */
            clientIps?: NonEmptyArray<string>;
        }
    }
}

export { type IpRequest, getClientIp };
