import { existsSync } from "node:fs";
import { join, basename } from "node:path";
import { isMiddleware, isMiddlewareFactory } from "./define-middleware.js";
import { resolveModuleDefault } from "./interop.js";
import { pathToFileURL } from "node:url";
// ── 支持的文件扩展名（按优先级排列）──────────────────────────
const EXTENSIONS = [".ts", ".js", ".mjs", ".cjs"];
// ── 主函数 ────────────────────────────────────────────────────
/**
 * loadMiddlewares — 按白名单加载中间件，构建 MiddlewareRegistry
 *
 * @param middlewaresDir  src/middlewares/ 目录的绝对路径
 * @param declarations    config.middlewares 白名单声明数组
 * @param logger          VextLogger 实例（输出兼容性警告）
 * @returns MiddlewareRegistry（name → { handler, defaultOptions, kind }）
 *
 * @example
 * ```typescript
 * // bootstrap 内部
 * const middlewareDefs = await loadMiddlewares(
 *   path.join(rootDir, 'src/middlewares'),
 *   app.config.middlewares,
 *   app.logger,
 * )
 * ```
 */
export async function loadMiddlewares(middlewaresDir, declarations, logger, lifecycleLevel = "concise") {
    const registry = {};
    // 白名单为空 → 无中间件需要加载，直接返回
    if (!declarations || declarations.length === 0) {
        return registry;
    }
    for (const decl of declarations) {
        const name = typeof decl === "string" ? decl : decl.name;
        const defaultOptions = typeof decl === "string" ? undefined : decl.options;
        // ── 1. 查找文件（多扩展名）─────────────────────────────
        const fullPath = resolveFile(middlewaresDir, name);
        if (!fullPath) {
            throw new Error(`[vextjs] Middleware "${name}" declared in config/default.ts\n` +
                `         but no matching file found in src/middlewares/.\n` +
                `         Searched: ${EXTENSIONS.map((e) => `${name}${e}`).join(", ")}`);
        }
        // ── 2. 动态 import ────────────────────────────────────
        const mod = await importMiddlewareFile(fullPath, name);
        const handler = resolveModuleDefault(mod);
        if (!handler) {
            throw new Error(`[vextjs] src/middlewares/${basename(fullPath)} has no default export.\n` +
                `         Must export default defineMiddleware(fn) or defineMiddlewareFactory(fn).`);
        }
        // ── 3. 检测中间件类型（显式标记优先，运行时推断兜底）───
        let kind;
        if (isMiddlewareFactory(handler)) {
            kind = "factory";
        }
        else if (isMiddleware(handler)) {
            kind = "middleware";
        }
        else if (typeof handler === "function") {
            // 兜底：未使用 defineMiddleware / defineMiddlewareFactory 包装
            // 退化为运行时推断（defaultOptions 存在 → factory，否则 → middleware）
            kind = defaultOptions !== undefined ? "factory" : "middleware";
            logger.warn(`[vextjs] middlewares/${basename(fullPath)}: export default without ` +
                `defineMiddleware() / defineMiddlewareFactory() is deprecated. ` +
                `Please wrap your middleware for explicit type declaration.`);
        }
        else {
            throw new Error(`[vextjs] src/middlewares/${basename(fullPath)} default export is not a function.\n` +
                `         Expected defineMiddleware(fn) or defineMiddlewareFactory(fn).\n` +
                `         Got: ${typeof handler}`);
        }
        // ── 4. 声明一致性检查 ─────────────────────────────────
        //
        // 如果白名单声明了 options，但文件导出的是 defineMiddleware（普通中间件），
        // 说明声明与实现不匹配 → Fail Fast。
        //
        if (kind === "middleware" && defaultOptions !== undefined) {
            throw new Error(`[vextjs] Middleware "${name}" is declared with options in config,\n` +
                `         but src/middlewares/${basename(fullPath)} exports defineMiddleware() (not a factory).\n` +
                `         Use defineMiddlewareFactory() if this middleware accepts options.`);
        }
        // ── 5. 写入 registry ──────────────────────────────────
        registry[name] = {
            handler: handler,
            defaultOptions,
            kind,
        };
    }
    if (Object.keys(registry).length > 0) {
        const names = Object.keys(registry);
        logger.info(`[vextjs] ${names.length} middleware(s) loaded`);
        if (lifecycleLevel === "verbose") {
            logger.info(`[middleware-loader] ${names.join(", ")}`);
        }
    }
    return registry;
}
// ── 中间件解析（路由引用时使用）──────────────────────────────
/**
 * resolveMiddleware — 从 registry 中解析单个中间件引用
 *
 * 路由 options.middlewares 中的每个引用（字符串或 { name, options }）
 * 通过此函数从 registry 中取出并实例化：
 *   - 普通中间件 → 直接返回 handler
 *   - 工厂中间件 → 使用路由覆盖 options 或默认 options 调用工厂
 *
 * @param ref      路由中的中间件引用
 * @param registry 已构建的中间件注册表
 * @returns 实例化后的 VextMiddleware
 * @throws 引用的中间件不在 registry 中 / 类型不匹配
 */
export function resolveMiddleware(ref, registry) {
    const name = typeof ref === "string" ? ref : ref.name;
    const overrideOpts = typeof ref === "string" ? undefined : ref.options;
    const entry = registry[name];
    if (!entry) {
        throw new Error(`[vextjs] Middleware "${name}" is not registered.\n` +
            `         Available middlewares: ${Object.keys(registry).join(", ") || "(none)"}\n` +
            `         Make sure "${name}" is declared in config/default.ts middlewares array.`);
    }
    // ── 工厂中间件 → 调用工厂 ─────────────────────────────────
    if (entry.kind === "factory") {
        // 参数优先级：路由覆盖 > 白名单默认值
        const finalOptions = overrideOpts ?? entry.defaultOptions;
        // 工厂中间件在无 options 时也允许调用（options 为 undefined）
        // 具体是否需要 options 由工厂函数自身决定
        const factory = entry.handler;
        return factory(finalOptions);
    }
    // ── 普通中间件 → 直接使用 ─────────────────────────────────
    if (overrideOpts !== undefined) {
        throw new Error(`[vextjs] Middleware "${name}" is not a factory and does not accept options.\n` +
            `         Remove the options or use defineMiddlewareFactory() in the middleware file.`);
    }
    return entry.handler;
}
/**
 * resolveMiddlewares — 批量解析中间件引用列表
 *
 * 将路由 options.middlewares 数组中的所有引用解析为 VextMiddleware 数组。
 *
 * @param refs     中间件引用列表
 * @param registry 已构建的中间件注册表
 * @returns VextMiddleware 数组（按声明顺序）
 */
export function resolveMiddlewares(refs, registry) {
    return refs.map((ref) => resolveMiddleware(ref, registry));
}
/**
 * validateMiddlewareRefs — 启动时统一验证所有路由的中间件引用
 *
 * 在所有路由加载完成后调用，检查每条路由引用的中间件名称
 * 是否都在 registry 中存在。不存在则 Fail Fast。
 *
 * 这是 router-loader 在注册所有路由后的最后一道防线，
 * 确保不会有运行时才暴露的"中间件未注册"错误。
 *
 * @param routeDefs      所有加载的路由定义对象
 * @param registry       已构建的中间件注册表
 * @throws 引用的中间件名称不在 registry 中
 */
export function validateMiddlewareRefs(routeDefs, registry) {
    for (const def of routeDefs) {
        for (const route of def.routes) {
            const refs = route.options.middlewares;
            if (!refs || refs.length === 0)
                continue;
            for (const ref of refs) {
                const name = typeof ref === "string" ? ref : ref.name;
                if (!registry[name]) {
                    throw new Error(`[vextjs] Route ${route.method} references middleware "${name}" which is not registered.\n` +
                        `         Source: ${def.sourceFile}\n` +
                        `         Available middlewares: ${Object.keys(registry).join(", ") || "(none)"}\n` +
                        `         Make sure "${name}" is declared in config/default.ts middlewares array.`);
                }
            }
        }
    }
}
// ── 内部辅助函数 ──────────────────────────────────────────────
/**
 * resolveFile — 在 middlewaresDir 下查找指定 name 对应的文件
 *
 * 按扩展名优先级依次查找：.ts → .js → .mjs → .cjs
 * 返回找到的第一个文件的完整路径，或 null。
 *
 * @param middlewaresDir 中间件目录的绝对路径
 * @param name          中间件名称（如 'auth'、'rate-limit'）
 * @returns 完整文件路径或 null
 */
function resolveFile(middlewaresDir, name) {
    for (const ext of EXTENSIONS) {
        const full = join(middlewaresDir, `${name}${ext}`);
        if (existsSync(full))
            return full;
    }
    return null;
}
/**
 * importMiddlewareFile — 动态 import 中间件文件
 *
 * 将文件路径转为 file:// URL 后进行 dynamic import。
 * 错误时包装为 vextjs 错误。
 *
 * @param fullPath 文件的绝对路径
 * @param name     中间件名称（用于错误信息）
 * @returns 模块对象
 */
async function importMiddlewareFile(fullPath, name) {
    try {
        const fileUrl = pathToFileUrl(fullPath);
        return await import(fileUrl);
    }
    catch (err) {
        throw new Error(`[vextjs] Failed to import middleware "${name}".\n` +
            `         File: ${fullPath}\n` +
            `         ${err.message}`);
    }
}
/**
 * 将文件系统路径转为 file:// URL
 *
 * dynamic import 在 Windows 上需要 file:// 协议前缀才能正确加载。
 */
function pathToFileUrl(filePath) {
    return pathToFileURL(filePath).href;
}
