import type { VextLogger } from "../types/app.js";
import type { VextRequest } from "../types/request.js";
import type { VextResponse } from "../types/response.js";
/**
 * fetch.ts — app.fetch 内置 HTTP 客户端
 *
 * 封装 Node.js 18+ 内置 fetch，提供：
 *   1. 自动传播 requestId（从 requestContext AsyncLocalStorage 读取）
 *   2. 结构化日志记录（出站请求 method/url/status/duration）
 *   3. 超时控制（AbortController + setTimeout）
 *   4. 快捷方法（get/post/put/patch/delete）
 *   5. create() 工厂（baseURL + 默认配置）
 *   6. proxy() / proxy.<target>() 请求代理能力（仅根 app.fetch 暴露）
 *
 * 挂载位置：app.fetch（与 app.logger / app.throw 同级）
 *
 * 与 requestContext 的关系：
 *   requestId 中间件在请求进入时将 requestId 写入 requestContext store。
 *   app.fetch 在发送出站请求时从 requestContext.getStore() 读取 requestId，
 *   自动注入到出站请求的 x-request-id 头，实现跨服务请求追踪。
 *
 * 配置项（config.fetch）：
 *   - timeout:          全局默认请求超时（毫秒，默认 10000）
 *   - retry:            默认重试次数（仅幂等方法，默认 0）
 *   - retryDelay:       默认重试间隔（毫秒，默认 1000）
 *   - propagateHeaders: 除 x-request-id 外还需自动传播的请求头
 *   - proxy:            上游代理目标列表（仅根 app.fetch.proxy 使用）
 *
 * 超时配置优先级：
 *   单次请求 init.timeout > create() 的 options.timeout > config.fetch.timeout
 *
 * 当前版本未暴露 app.setFetch() 公共 API；自定义实现需在框架内部注入。
 *
 * @module lib/fetch
 * @see IMPLEMENTATION-PLAN.md 任务 1.8b
 * @see 06d-fetch.md §1~§4
 */
/**
 * 扩展的 fetch 初始化选项
 *
 * 在标准 RequestInit 基础上增加 vext 特有的配置项：
 *   - timeout:             请求超时（毫秒）
 *   - retry:               重试次数（仅幂等方法）
 *   - retryDelay:          重试间隔（毫秒）或指数退避函数
 *   - propagateRequestId:  是否自动注入 requestId 头
 *   - propagateHeaders:    额外需要传播的请求头
 */
export interface VextFetchInit extends RequestInit {
    /** 请求超时（毫秒），默认使用全局配置 config.fetch.timeout */
    timeout?: number;
    /** 重试次数（仅对幂等方法 GET/HEAD/OPTIONS/PUT/DELETE 生效），默认 0 */
    retry?: number;
    /** 重试间隔（毫秒），默认 1000；支持函数形式实现指数退避 */
    retryDelay?: number | ((attempt: number) => number);
    /**
     * 是否自动注入 requestId 头
     * 默认 true；设为 false 可禁用（如调用不支持此头的外部 API）
     */
    propagateRequestId?: boolean;
    /**
     * 自定义传播头（除 requestId 外还要传播的请求头）
     * 例如 ['x-trace-id', 'x-tenant-id']
     */
    propagateHeaders?: string[];
}
/**
 * create() 工厂选项
 */
export interface VextFetchClientOptions {
    /** 基础 URL，所有请求自动拼接 */
    baseURL: string;
    /** 默认请求头 */
    headers?: Record<string, string>;
    /** 默认超时 */
    timeout?: number;
    /** 默认重试 */
    retry?: number;
    /** 默认重试间隔（毫秒）或指数退避函数 */
    retryDelay?: number | ((attempt: number) => number);
}
/**
 * 可写入代理上游的请求头值。
 */
type ProxyHeaderValue = string | number | boolean | null | undefined;
type ProxyRequestBody = Exclude<RequestInit["body"], null | undefined> | Buffer | Uint8Array;
/**
 * 代理动态注入 headers 的上下文。
 */
export interface VextFetchProxyHeaderContext {
    req: VextRequest;
    target?: VextFetchProxyTargetConfig;
    options: VextFetchProxyOptions;
}
/**
 * 代理 headers 配置。
 */
export type VextFetchProxyHeaders = Record<string, ProxyHeaderValue> | ((ctx: VextFetchProxyHeaderContext) => Record<string, ProxyHeaderValue> | Promise<Record<string, ProxyHeaderValue>>);
/**
 * config.fetch.proxy[] 的单个代理目标配置。
 */
export interface VextFetchProxyTargetConfig {
    /** 目标名称，对应 app.fetch.proxy.<name>() */
    name: string;
    /** 上游基础地址，会与调用时 options.path 拼接 */
    baseURL: string;
    /** 目标级固定 headers，优先级最低 */
    headers?: Record<string, string>;
    /** 从当前 req.headers 白名单透传的 header 名称 */
    forwardHeaders?: string[];
    /** 目标级动态注入 headers，覆盖 headers / forwardHeaders */
    defaultInjectHeaders?: VextFetchProxyHeaders;
    /** 是否允许从当前请求透传原始 Authorization header */
    allowAuthorizationForward?: boolean;
    /** 目标级超时（毫秒） */
    timeout?: number;
    /** 目标级重试次数，表示额外尝试次数 */
    retry?: number;
    /** 目标级重试间隔（毫秒）或指数退避函数 */
    retryDelay?: number | ((attempt: number) => number);
}
/**
 * app.fetch.proxy 调用选项。
 */
export interface VextFetchProxyOptions {
    /** 命名目标模式下必传：拼接到 target.baseURL 的路径 */
    path?: string;
    /** 直接 URL 模式下必传：app.fetch.proxy(req, res, { url }) */
    url?: string;
    /** 默认使用当前 req.method */
    method?: string;
    /** 默认透传当前 req.query；同名 key 由 options.query 覆盖 */
    query?: Record<string, ProxyHeaderValue>;
    /** 显式请求体；未传时非 GET/HEAD 会读取当前 req 原始 body Buffer */
    body?: ProxyRequestBody;
    /** 读取当前 req 原始 body 的最大字节数 */
    maxBodySize?: number;
    /** 调用级固定 headers，覆盖目标级配置和透传 headers */
    headers?: Record<string, string>;
    /** 调用级追加 header 透传白名单 */
    forwardHeaders?: string[];
    /** 调用级动态注入 headers，优先级最高 */
    injectHeaders?: VextFetchProxyHeaders;
    /** 调用级是否允许透传原始 Authorization header */
    allowAuthorizationForward?: boolean;
    /** 调用级超时（毫秒） */
    timeout?: number;
    /** 调用级重试次数，表示额外尝试次数 */
    retry?: number;
    /** 调用级重试间隔（毫秒）或指数退避函数 */
    retryDelay?: number | ((attempt: number) => number);
}
/**
 * 命名目标代理处理函数。
 */
export type VextFetchProxyHandler = (req: VextRequest, res: VextResponse, options: VextFetchProxyOptions) => Promise<void>;
/**
 * app.fetch.proxy 接口。
 *
 * - app.fetch.proxy(req, res, { url })：直接 URL 代理
 * - app.fetch.proxy.<target>(req, res, { path })：config.fetch.proxy[] 目标代理
 */
export type VextFetchProxy = {
    (req: VextRequest, res: VextResponse, options: VextFetchProxyOptions): Promise<void>;
} & Record<string, VextFetchProxyHandler>;
/**
 * app.fetch.create() 返回的纯出站 HTTP 客户端。
 *
 * 子客户端不暴露 proxy，避免 app.fetch.create().proxy 带来额外心智负担。
 */
export interface VextFetchClient {
    (input: string | URL | Request, init?: VextFetchInit): Promise<Response>;
    get(url: string, init?: VextFetchInit): Promise<Response>;
    post(url: string, body?: unknown, init?: VextFetchInit): Promise<Response>;
    put(url: string, body?: unknown, init?: VextFetchInit): Promise<Response>;
    patch(url: string, body?: unknown, init?: VextFetchInit): Promise<Response>;
    delete(url: string, init?: VextFetchInit): Promise<Response>;
    create(options: VextFetchClientOptions): VextFetchClient;
}
/**
 * 根 VextFetch 接口
 *
 * 既是可调用的函数（与原生 fetch 签名一致），
 * 又挂载了快捷方法（get/post/put/patch/delete）、create() 工厂和 proxy。
 */
export interface VextFetch extends VextFetchClient {
    proxy: VextFetchProxy;
    create(options: VextFetchClientOptions): VextFetchClient;
}
/**
 * fetch 模块配置（从 VextConfig 中提取）
 */
export interface VextFetchConfig {
    timeout?: number;
    retry?: number;
    retryDelay?: number | ((attempt: number) => number);
    propagateHeaders?: string[];
    proxy?: VextFetchProxyTargetConfig[];
}
type FetchConfig = VextFetchConfig;
/**
 * createVextFetch — 创建 app.fetch 内置 HTTP 客户端
 *
 * 在 bootstrap 阶段调用，将返回的 VextFetch 挂载到 app.fetch。
 *
 * @param logger          app.logger 实例（用于结构化日志）
 * @param fetchConfig     config.fetch 配置
 * @param requestIdHeader requestId 传播使用的头名称（默认 'x-request-id'）
 * @returns VextFetch 实例
 */
export declare function createVextFetch(logger: VextLogger, fetchConfig?: FetchConfig, requestIdHeader?: string): VextFetch;
export {};
