import type { VextApp, VextConfig, VextServices } from "../types/app.js";
/**
 * createTestApp 选项
 *
 * @see 10-testing.md §2.1
 */
export interface CreateTestAppOptions {
    /**
     * 覆盖默认配置（深度合并到 test 默认配置之上）
     */
    config?: Partial<VextConfig>;
    /**
     * 是否加载 src/plugins/（默认 false — 测试环境默认不加载插件）
     */
    plugins?: boolean;
    /**
     * 手动注册插件（替代自动扫描，精确控制测试依赖）
     */
    setupPlugins?: (app: VextApp) => Promise<void> | void;
    /**
     * 是否加载 `src/services/`（默认 true）
     *
     * 为 `true` 时，`service-loader` 扫描 `src/services/` 并自动加载所有 `.ts` 服务文件。
     * `.ts` 文件通过 esbuild bundle 编译后加载，完整支持：
     *   - TypeScript 语法及类型擦除
     *   - 服务文件内部的 `.js` 扩展名 import（TypeScript ESM 约定）
     *   - 相对路径模块依赖（esbuild bundle 内联解析）
     *
     * **单元测试推荐**：设为 `false` + 配合 `mockServices`，避免加载真实服务：
     *
     * ```typescript
     * await createTestApp({
     *   services: false,
     *   mockServices: { user: mockUserService },
     * })
     * ```
     */
    services?: boolean;
    /**
     * 手动注入 mock services（覆盖 service-loader 扫描结果）
     *
     * 如果同时 services=true，先加载真实 services，再用 mockServices 覆盖。
     * 如果 services=false，仅使用 mockServices。
     */
    mockServices?: Partial<VextServices>;
    /**
     * 是否加载 src/routes/（默认 true — 集成测试需要路由）
     */
    routes?: boolean;
    /**
     * 是否加载 src/middlewares/（默认 true）
     */
    middlewares?: boolean;
    /**
     * 项目根目录（默认 process.cwd()）
     *
     * 用于定位 src/routes、src/services 等目录。
     */
    rootDir?: string;
}
/**
 * 测试 App 实例
 *
 * @see 10-testing.md §2.1
 */
export interface TestApp {
    /** 底层 VextApp 实例 */
    app: VextApp;
    /**
     * 发送模拟 HTTP 请求（无需启动 HTTP 服务器）
     * 类似 supertest 的 API 风格
     */
    request: TestRequest;
    /**
     * 关闭 test app（触发 onClose 钩子、清理资源）
     * 务必在 afterEach / afterAll 中调用
     */
    close(): Promise<void>;
}
/**
 * HTTP 请求模拟器
 *
 * @see 10-testing.md §6
 */
export interface TestRequest {
    get(path: string): TestRequestBuilder;
    post(path: string): TestRequestBuilder;
    put(path: string): TestRequestBuilder;
    patch(path: string): TestRequestBuilder;
    delete(path: string): TestRequestBuilder;
    options(path: string): TestRequestBuilder;
    head(path: string): TestRequestBuilder;
}
/**
 * 链式请求构造器
 *
 * 支持链式调用设置请求参数，最终通过 await 或 .then() 执行请求。
 *
 * @see 10-testing.md §6
 */
export interface TestRequestBuilder extends PromiseLike<TestResponse> {
    /** 设置请求头 */
    set(key: string, value: string): this;
    /** 设置多个请求头 */
    headers(headers: Record<string, string>): this;
    /** 设置 query 参数 */
    query(params: Record<string, string | number | boolean>): this;
    /** 设置请求体（自动序列化为 JSON，设置 Content-Type） */
    send(body: unknown): this;
    /** 设置 Content-Type */
    type(contentType: string): this;
}
/**
 * 模拟 HTTP 响应
 *
 * @see 10-testing.md §6
 */
export interface TestResponse {
    /** HTTP 状态码 */
    status: number;
    /** 响应头 */
    headers: Record<string, string>;
    /** 自动解析的 JSON 响应体 */
    body: any;
    /** 原始响应文本 */
    text: string;
}
/**
 * createTestApp — 测试用 App 工厂
 *
 * 零配置创建测试用 app 实例，支持 mock services、路由级集成测试。
 * 内部不启动 HTTP 服务器，通过 adapter.buildHandler() 模拟请求。
 *
 * ---
 *
 * ### TypeScript 服务文件与 ESM 加载
 *
 * 当 `services: true`（默认）时，`createTestApp()` 调用 `loadServices(app, 'src/services/')`
 * 加载 `.ts` 源文件。`service-loader` 内部会自动用 esbuild 将 `.ts` 文件
 * bundle 编译为 `.mjs` 后加载，解决两个原生问题：
 *
 *   1. `ERR_UNKNOWN_FILE_EXTENSION` — Node.js 原生 ESM 不支持 `.ts` 扩展名
 *   2. `.js → .ts` 重映射缺失 — TypeScript ESM 约定使用 `.js` 扩展名，
 *      Node.js / Vite resolver 均不自动回退到 `.ts`；
 *      esbuild bundle 阶段已完整处理此映射
 *
 * **单元测试推荐**：若只测试路由逻辑，使用 `mockServices` 跳过真实服务加载，
 * 速度更快且完全隔离：
 *
 * ```typescript
 * const t = await createTestApp({
 *   services: false,   // 不加载真实 .ts 服务文件
 *   mockServices: {
 *     user: { findAll: vi.fn().mockResolvedValue([]) },
 *   },
 * })
 * ```
 *
 * **集成测试**：保持 `services: true`（默认），`service-loader` 自动处理编译。
 *
 * @param options 创建选项（全部可选）
 * @returns 包含 app、request、close 的测试 App 实例
 *
 * @example
 * ```typescript
 * const t = await createTestApp({
 *   routes: true,
 *   mockServices: {
 *     user: { findAll: async () => ({ list: [], total: 0 }) },
 *   },
 * })
 * const res = await t.request.get('/users/list').query({ page: 1, limit: 10 })
 * expect(res.status).toBe(200)
 * await t.close()
 * ```
 *
 * @see 10-testing.md §2（接口规范）
 * @see 10-testing.md §11（内部实现概览）
 * @see IMPLEMENTATION-PLAN.md 任务 1.19
 */
export declare function createTestApp(options?: CreateTestAppOptions): Promise<TestApp>;
