import { Hono } from "hono";
import { createServer } from "node:http";
import crypto from "node:crypto";
import { createVextRequest } from "./request.js";
import { createVextResponse, createResponseBox } from "./response.js";
import { requestContext } from "../../lib/request-context.js";
import { resolveRouteBodyParserConfig } from "../../lib/middlewares/body-parser.js";
import { applyServerConfig, createNodeServerOptions, } from "../../lib/server-config.js";
/**
 * 中间件链执行器（洋葱模型）
 *
 * 按顺序执行中间件链中的每个中间件，
 * 每个中间件通过 await next() 调用下一个中间件。
 * next() 返回后可执行 after-middleware 逻辑（洋葱模型回溯）。
 *
 * P0-3 修复：next 为 async 函数，类型与 VextMiddleware 的
 * next: () => Promise<void> 对齐。用户中间件应 await next()
 * 以支持洋葱模型的 after-middleware 逻辑。
 *
 * 🆕 性能优化：使用递归调度函数替代每请求创建闭包。
 * dispatch 函数通过参数传递 index，避免在闭包中捕获可变变量，
 * V8 对固定参数签名的函数有更好的内联优化。
 *
 * @param chain 中间件执行链（已组装完毕，含全局 + 路由级 + validate + handler）
 * @param req   VextRequest 实例
 * @param res   VextResponse 实例
 */
async function executeChain(chain, req, res) {
    const len = chain.length;
    if (len === 1) {
        await chain[0](req, res, _noop);
        return;
    }
    if (len === 2) {
        await chain[0](req, res, async () => {
            await chain[1](req, res, _noop);
        });
        return;
    }
    if (len === 3) {
        await chain[0](req, res, async () => {
            await chain[1](req, res, async () => {
                await chain[2](req, res, _noop);
            });
        });
        return;
    }
    if (len === 4) {
        await chain[0](req, res, async () => {
            await chain[1](req, res, async () => {
                await chain[2](req, res, async () => {
                    await chain[3](req, res, _noop);
                });
            });
        });
        return;
    }
    async function dispatch(i) {
        if (i >= len)
            return;
        const middleware = chain[i];
        await middleware(req, res, () => dispatch(i + 1));
    }
    await dispatch(0);
}
const _noop = async () => { };
/**
 * createHonoAdapter — 创建基于 Hono 的 VextAdapter 实例
 *
 * 将 Hono 作为底层 HTTP 路由引擎，实现 VextAdapter 接口。
 * 所有路由 / 中间件 / 错误处理都通过 Hono 的路由匹配 + vext 的中间件链执行。
 *
 * 架构说明：
 *   - Hono 仅用于路由匹配（trie router），不使用 Hono 自带的中间件机制
 *   - 中间件链执行由 vext 自己的 executeChain 实现（洋葱模型）
 *   - 请求 / 响应对象在 Hono route handler 内转换为 VextRequest / VextResponse
 *   - 全局中间件通过 registerMiddleware() 收集，在每个路由执行时拼接到链头
 *
 * HTTP 服务器：
 *   - 使用 Node.js 原生 http.createServer
 *   - 将 Node.js IncomingMessage 转为 Web Request 交给 Hono 处理
 *   - 将 Hono 返回的 Web Response 写回 Node.js ServerResponse
 *   - buildHandler() 返回 Node.js (req, res) handler，用于 dev 模式热重载替换
 *
 * Response 捕获机制（ResponseBox）：
 *   Hono 的 route handler 必须返回 Response 对象。但 vext 的 executeChain 是 void 的，
 *   VextResponse 的发送方法（json/text/...）内部调用 c.json()/c.text() 等 Hono API，
 *   这些 API 返回 Response 对象。通过 ResponseBox 容器捕获这些 Response，
 *   route handler 最后从 box.value 取出 Response 返回给 Hono。
 *
 * @param app VextApp 实例（用于传递给 createVextRequest 的 app 引用）
 * @returns VextAdapter 实例
 */
export function createHonoAdapter(app) {
    const hono = new Hono();
    const globalMiddlewares = [];
    let errorHandler = null;
    /** 全局中间件是否已冻结（listen/buildHandler 后不再变更） */
    const _globalFrozen = false;
    // ── 🆕 5.7: 缓存 ALS 开关（避免热路径重复读取 config）────
    const alsEnabled = app.config.requestContext?.enabled !== false;
    return {
        name: "hono",
        registerMiddleware(middleware) {
            globalMiddlewares.push(middleware);
        },
        registerRoute(method, path, chain, routeOptions = {}) {
            // 使用 hono.on() 以支持所有 HTTP 方法（包括 HEAD / OPTIONS）
            // hono.on() 接受方法字符串数组和路径
            const upperMethod = method.toUpperCase();
            // 🆕 性能优化：延迟预组装中间件链
            //
            // 注册路由时 globalMiddlewares 尚未完成收集（bootstrap 步骤⑥在步骤⑤之后），
            // 因此无法在 registerRoute 时预组装。改为在首次请求时组装并缓存。
            // 后续请求直接复用已组装的链，避免每请求 [...spread] 开销。
            //
            let prebuiltChain = null;
            hono.on(upperMethod, path, async (c) => {
                const req = createVextRequest(c, app);
                req._routeOptions = routeOptions;
                const routeBodyParser = resolveRouteBodyParserConfig(routeOptions);
                if (routeBodyParser) {
                    req._routeBodyParser = routeBodyParser;
                }
                // F-01: 注入路由模板字符串（低基数，适合 OTEL/Prometheus 指标标签）
                // path 是 registerRoute 的参数，在此 closure 中直接可访问
                req.route = path;
                // 创建 ResponseBox 用于捕获 VextResponse 发送方法产生的 Response
                const box = createResponseBox();
                // 延迟绑定 requestId：传入 getter 确保 json() 实际调用时才取值
                // 此时 requestId 必然已由 requestIdMiddleware 设置到 req.requestId
                const res = createVextResponse(c, () => req.requestId, box);
                // 在 AsyncLocalStorage 请求上下文中执行整个中间件链
                // 确保 app.throw 等内部方法能通过 requestContext.getStore() 访问请求级数据
                //
                // 🆕 5.7: 当 requestContext.enabled === false 时跳过 ALS 包裹，
                // 直接执行中间件链，预估 +3-8% RPS。
                //
                const runChain = async () => {
                    try {
                        // 🆕 预组装中间件链（首次请求时组装，后续复用）
                        if (prebuiltChain === null) {
                            prebuiltChain = globalMiddlewares.concat(chain);
                        }
                        await executeChain(prebuiltChain, req, res);
                    }
                    catch (err) {
                        if (errorHandler) {
                            // P2-6 修复：errorHandler 自身抛异常的边界保护
                            // 防止 errorHandler 内部失败（如 logger 写入 DB transport 失败）
                            // 导致异常传播到 Hono 的 catch，产生非 JSON 的纯文本 500
                            try {
                                errorHandler(err, req, res);
                            }
                            catch (handlerError) {
                                try {
                                    res.rawJson({ code: 500, message: "Internal Server Error" }, 500);
                                }
                                catch {
                                    // 完全放弃，让底层框架的 catch 处理
                                    throw handlerError;
                                }
                            }
                        }
                        else {
                            throw err;
                        }
                    }
                    // 从 ResponseBox 中获取 VextResponse 发送方法捕获的 Response
                    // 如果 handler 没有调用任何发送方法，返回空的 200 Response 作为兜底
                    return box.value ?? c.body(null);
                };
                if (alsEnabled) {
                    return requestContext.run({ requestId: "", locale: undefined }, runChain);
                }
                else {
                    return runChain();
                }
            });
        },
        registerErrorHandler(handler) {
            errorHandler = handler;
        },
        registerNotFound(handler) {
            hono.notFound(async (c) => {
                const req = createVextRequest(c, app);
                const box = createResponseBox();
                // P2-5 修复：notFound 不经过中间件链，requestId 中间件不会执行。
                // 内联生成 requestId，确保 404 响应也有有效的 requestId
                if (!req.requestId) {
                    const headerName = app.config.requestId?.header ?? "x-request-id";
                    req.requestId =
                        req.headers[headerName] || crypto.randomUUID();
                }
                const res = createVextResponse(c, () => req.requestId, box);
                // 🆕 5.7: ALS 可配置跳过
                const runNotFound = async () => {
                    const noop = async () => { };
                    await handler(req, res, noop);
                };
                if (alsEnabled) {
                    await requestContext.run({ requestId: req.requestId, locale: undefined }, runNotFound);
                }
                else {
                    await runNotFound();
                }
                // 从 ResponseBox 获取 notFound handler 生成的 Response
                // 如果 handler 没有发送任何响应，返回默认的 404 JSON
                return box.value ?? c.json({ code: 404, message: "Not Found" }, 404);
            });
        },
        async listen(port, host = "0.0.0.0", options) {
            const requestHandler = this.buildHandler();
            return new Promise((resolve, reject) => {
                const server = createServer(createNodeServerOptions(options?.server), requestHandler);
                applyServerConfig(server, options?.server);
                server.on("error", (err) => {
                    reject(err);
                });
                server.listen(port, host, () => {
                    const addr = server.address();
                    const actualPort = typeof addr === "object" && addr !== null ? addr.port : port;
                    const actualHost = typeof addr === "object" && addr !== null
                        ? (addr.address ?? host)
                        : host;
                    resolve({
                        port: actualPort,
                        host: actualHost,
                        close() {
                            return new Promise((resolveClose, rejectClose) => {
                                server.close((err) => {
                                    if (err) {
                                        rejectClose(err);
                                    }
                                    else {
                                        resolveClose();
                                    }
                                });
                            });
                        },
                    });
                });
            });
        },
        buildHandler() {
            // 将 Hono 的 fetch handler 转为 Node.js 的 (req, res) 形式
            //
            // 流程：
            //   1. 将 Node.js IncomingMessage 转为 Web Request 对象
            //   2. 调用 Hono 的 fetch() 处理请求
            //   3. 将返回的 Web Response 写入 Node.js ServerResponse
            return (nodeReq, nodeRes) => {
                // 构造 Web Request URL
                const protocol = "http";
                const host = nodeReq.headers.host ??
                    `localhost:${nodeReq.socket.address()?.port ?? 3000}`;
                const url = `${protocol}://${host}${nodeReq.url ?? "/"}`;
                // 判断请求是否有 body
                const method = (nodeReq.method ?? "GET").toUpperCase();
                const hasBody = method !== "GET" && method !== "HEAD";
                // 将 Node.js IncomingMessage 转为 Web ReadableStream（用于 POST/PUT 等有 body 的请求）
                let body = null;
                if (hasBody) {
                    body = new ReadableStream({
                        start(controller) {
                            nodeReq.on("data", (chunk) => {
                                controller.enqueue(new Uint8Array(chunk));
                            });
                            nodeReq.on("end", () => {
                                controller.close();
                            });
                            nodeReq.on("error", (err) => {
                                controller.error(err);
                            });
                        },
                    });
                }
                // 转换 Node.js 请求头为 Headers 对象
                const headers = new Headers();
                const rawHeaders = nodeReq.rawHeaders;
                for (let i = 0; i < rawHeaders.length; i += 2) {
                    const key = rawHeaders[i];
                    const value = rawHeaders[i + 1];
                    if (key && value) {
                        headers.append(key, value);
                    }
                }
                // 构造 Web Request 的 init 选项
                const requestInit = {
                    method,
                    headers,
                };
                // 仅在有 body 时设置 body 和 duplex
                if (body) {
                    requestInit.body = body;
                    // duplex 是 Node.js 中流式请求体所需的选项
                    // TypeScript 类型定义中尚未包含此属性，但运行时需要
                    requestInit.duplex = "half";
                }
                // 构造 Web Request
                const webRequest = new Request(url, requestInit);
                // 通过 env 传递 Node.js 原始对象，供 createVextRequest 读取 socket 信息
                const env = { incoming: nodeReq, outgoing: nodeRes };
                // 调用 Hono 的 fetch handler，其返回值可能是 Response 或 Promise<Response>
                const result = hono.fetch(webRequest, env);
                // 统一处理为 Promise
                const responsePromise = result instanceof Promise ? result : Promise.resolve(result);
                responsePromise
                    .then(async (webResponse) => {
                    // 将 Web Response 写入 Node.js ServerResponse
                    nodeRes.statusCode = webResponse.status;
                    // 设置响应头
                    webResponse.headers.forEach((value, key) => {
                        nodeRes.setHeader(key, value);
                    });
                    // 写入响应体
                    if (webResponse.body) {
                        const reader = webResponse.body.getReader();
                        try {
                            while (true) {
                                const { done, value } = await reader.read();
                                if (done)
                                    break;
                                nodeRes.write(value);
                            }
                        }
                        catch {
                            // 客户端可能已断开
                        }
                        finally {
                            nodeRes.end();
                        }
                    }
                    else {
                        nodeRes.end();
                    }
                })
                    .catch(() => {
                    // Hono 内部未捕获的异常（理论上不应到达此处，因为有 errorHandler）
                    if (!nodeRes.headersSent) {
                        nodeRes.statusCode = 500;
                        nodeRes.setHeader("Content-Type", "application/json");
                        nodeRes.end(JSON.stringify({
                            code: 500,
                            message: "Internal Server Error",
                        }));
                    }
                });
            };
        },
    };
}
