/*
 * Copyright (c) 2025 SimcuTeam. All rights reserved.
 * 遵循 MIT 许可证。
 *
 * 根命名空间 SimApi 下的静态类 SimApiExtensions（AddSimApi + UseSimApi）。
 * 本文件同时是 simapi 根包的入口锚点：cjpm 要求 src 根目录至少有一个 .cj 文件，
 * 否则不会扫描 src 子目录（helpers/controllers/...），整个包将编译为空。
 *
 * 使用方式：
 * ```
 * let builder = WebHost.createBuilder(args)
 * builder.services.addLogging()
 * SimApiExtensions.addSimApi(builder) { options =>
 *     options.enableSimApiAuth = true
 * }
 * let host = builder.build()
 * SimApiExtensions.useSimApi(host)
 * host.run()
 * ```
 */

package simcu::simapi

import std.collection.*
import std.convert.*
import std.reflect.*
import std.time.*
import std.unicode.*
import soulsoft_web_http.*
import soulsoft_web_hosting.*
import soulsoft_web_mvc.*
import soulsoft_web_mvc.applicationModels.*
import soulsoft_web_mvc.routing.*
import soulsoft_web_cors.*
import soulsoft_web_routing.*
import soulsoft_extensions_injection.*
import soulsoft_extensions_logging.*
import simcu::simapi.authsdk.*
import simcu::simapi.communications.*
import simcu::simapi.configurations.*
import simcu::simapi.controllers.*
import simcu::simapi.helpers.*
import simcu::simapi.interfaces.*
import simcu::simapi.logger.*
import simcu::simapi.middlewares.*
import simcu::simapi.openapi.*
import simcu::simapi.openapi.annotations.*
import simcu::simapi.annotations.{SimApiAuth as SimApiAuthAnnotation}

/**
 * SimApi 扩展入口。
 */
public class SimApiExtensions {
    private init() {}

    /**
     * 注册 SimApi 服务到 WebHostBuilder（自动 addRouting + addControllers + 扫描控制器）。
     * @param builder 主机构建器。
     * @param configure 配置回调。
     * @return 当前构建器。
     */
    public static func addSimApi(builder: WebHostBuilder, configure: (SimApiOptions) -> Unit): WebHostBuilder {
        // 自动注册路由（对齐 builder.Services.AddRouting()）
        builder.services.addRouting()
        // 先构造配置，供后续按开关注册服务
        let options = SimApiOptions()
        configure(options)
        // 响应封装：
        // 启用时注册自定义 IRequestDelegateFactory 自动封装响应。
        // 必须在 addControllers 之前：soulsoft 用 tryAddSingleton 注册，先到先得，不会被覆盖。
        // 未启用时使用 soulsoft 默认派发（String→ContentResult / ISerializable→ObjectResult / 其余→204）。
        if (options.enableSimApiResponseFilter) {
            builder.services.addSingleton<IRequestDelegateFactory, SimApiRequestDelegateFactory>()
        }
        // 自动注册 MVC + 控制器（对齐 builder.Services.AddControllers()）
        // 自动扫描调用者包中的 Controller 子类
        let controllers = SimApiControllerScanner.scan()
        addControllers(builder.services, controllers)
        // 注册 SimApi 服务
        addSimApiCore(builder, options)
        return builder
    }

    /**
     * 注册 SimApi 服务（默认配置，自动扫描控制器）。
     * @param builder 主机构建器。
     * @return 当前构建器。
     */
    public static func addSimApi(builder: WebHostBuilder): WebHostBuilder {
        addSimApi(builder, {_ =>})
    }

    /**
     * 应用 SimApi 中间件与内置路由（日志输出）。
     * @param host 构建完成的主机。
     */
    public static func useSimApi(host: WebHost): Unit {
        let options = host.services.getOrThrow<SimApiOptions>()
        let loggerFactory = host.services.getOrThrow<ILoggerFactory>()
        // 分类名为 SimApiOptions 的全限定名
        let logger = loggerFactory.createLogger<SimApiOptions>()

        // ===== 基础信息 =====
        let now = DateTime.now()
        logger.info("当前时区: ${now.zoneId}")
        logger.info("主应用版本: ${SimApiUtil.appVersion}\nSimApi版本: ${SimApiUtil.simApiVersion}")

        // RedisCache
        if (!options.redisConfiguration.isEmpty()) {
            logger.info("开始配置 RedisCache ...")
        }

        // SimApiCache
        if (options.enableSimApiCache) {
            logger.info("开始配置 SimApiCache...")
        }

        // SimApiStorage（已实现：addSimApi 中注册 Scoped，桶初始化惰性执行；
        // 但 scoped 服务不能从根解析，故仅输出配置日志）
        if (options.enableSimApiStorage) {
            logger.info("开始配置 SimApiStorage...")
        }

        // SimApiHttpClient
        if (options.enableSimApiHttpClient) {
            logger.info(
                "开始配置 SimApiHttpClient...\n服务器地址: ${options.simApiHttpClientOptions.server}\nAppId: ${options.simApiHttpClientOptions.appId}\nAppkey: ${options.simApiHttpClientOptions.appKey}")
        }

        // Synapse（占位）
        if (options.enableSynapse) {
            logger.info("开始配置 SimApiSynapse...")
        }

        // SimApiJob（占位）
        if (options.enableJob) {
            logger.info("开始配置 SimApiJob ...")
        }

        // ===== 中间件与路由 =====
        // 挂载顺序（先挂载 = 外层）：ForwardedHeaders(L419) → CORS(L425) → AuthGate(L454) → Auth(L462)
        //   → 内置路由(L465-496) → Swagger(L502) → RequestLog(L519) → Exception(L525) → LowerUrl → Job

        // ForwardedHeaders（占位：soulsoft 暂无内置）
        if (options.enableForwardHeaders) {
            logger.info("开始配置ForwardedHeaders...")
        }

        // CORS
        if (options.enableCors) {
            logger.info("开始配置 Cors全部允许...")
            host.useCors()
        }

        // AuthGate
        if (options.enableSimApiAuthGate) {
            logger.info("开始配置 SimApiAuthGate...")
            host.use<SimApiAuthCenterMiddleware>()
        }

        // 认证中间件
        if (options.enableSimApiAuth) {
            logger.info("开始配置 SimApiAuth...")
            host.use<SimApiAuthMiddleware>()
        }

        // 内置路由：全部动态注册（路径由 SimApiRouteOptions 决定，不写死在控制器特性注解上）
        let routeOptions = options.simApiRouteOptions
        if (let Some(route) <- routeOptions.userInfoRoute) {
            host.mapPost(route, { context =>
                let controller = ActivatorUtilities.createInstance(context.services,
                    TypeInfo.of<SimApiCommonController>())
                if (let c: SimApiBaseController <- controller) {
                    c.bindRequestContext(context)
                }
                if (let c: SimApiCommonController <- controller) {
                    SimApiResultWriter.write(context, c.userInfo())
                }
            }).withOpenApi(SimApiDoc(tags: "认证", summary: "获取登录用户信息",groupNames:"*")).withSimApiAuth(SimApiAuthAnnotation()).withResponseType(TypeInfo.of<SimApiLoginItem>())
            logger.info("注册内置Route: UserInfo => ${route}")
        }
        if (let Some(route) <- routeOptions.logoutRoute) {
            host.mapPost(route, { context =>
                let controller = ActivatorUtilities.createInstance(context.services,
                    TypeInfo.of<SimApiAuthController>())
                if (let c: SimApiBaseController <- controller) {
                    c.bindRequestContext(context)
                }
                if (let c: SimApiAuthController <- controller) {
                    SimApiResultWriter.write(context, c.logout())
                }
            }).withOpenApi(SimApiDoc(tags: "认证", summary: "退出登录",groupNames:"*"))
            logger.info("注册内置Route: Logout => ${route}")
        }
        if (let Some(route) <- routeOptions.webConfigRoute) {
            host.mapGet(route, { context =>
                let controller = ActivatorUtilities.createInstance(context.services,
                    TypeInfo.of<SimApiCommonController>())
                if (let c: SimApiBaseController <- controller) {
                    c.bindRequestContext(context)
                }
                if (let c: SimApiCommonController <- controller) {
                    SimApiResultWriter.write(context, c.webConfig())
                }
            }).withOpenApi(SimApiDoc(tags: "公共", summary: "获取公共系统配置",groupNames:"*")).withResponseType(TypeInfo.of<HashMap<String, Any>>())
            host.mapPost(route, { context =>
                let controller = ActivatorUtilities.createInstance(context.services,
                    TypeInfo.of<SimApiCommonController>())
                if (let c: SimApiBaseController <- controller) {
                    c.bindRequestContext(context)
                }
                if (let c: SimApiCommonController <- controller) {
                    SimApiResultWriter.write(context, c.webConfig())
                }
            }).withOpenApi(SimApiDoc(tags: "公共", summary: "获取公共系统配置",groupNames:"*")).withResponseType(TypeInfo.of<HashMap<String, Any>>())
            logger.info("注册内置Route: WebConfig => ${route}")
        }


        // 请求日志中间件
        if (options.enableRequestLog) {
            logger.info("开始配置 SimApiRequestLog...")
            host.use<SimApiRequestLogMiddleware>()
        }

        // 异常中间件最后挂载（最内层）
        if (options.enableSimApiException) {
            logger.info("开始配置 SimApiException...")
            host.use<SimApiExceptionMiddleware>()
        }

        // URL 小写
        if (options.enableLowerUrl) {
            logger.info("开始配置使用URL小写...")
        }

        // SimApiJob Web 控制台（占位）
        if (options.enableJob && options.simApiJobOptions.dashboardUrl != None) {
            logger.info("开始配置 SimApiJob Web控制台...")
        }

        // 响应封装（已实现：addSimApi 中按开关注册 SimApiRequestDelegateFactory 自动封装，
        // 此处仅输出配置日志）
        if (options.enableSimApiResponseFilter) {
            logger.info("开始配置 SimApiResponseFilter...")
        }

        // 映射控制器端点
        let callSiteFactory = host.services.getOrThrow<IServiceProviderIsService>()
        if (callSiteFactory.isService<ApplicationPartManager>()) {
            host.mapControllers()
        }

        // SimApiDoc（OpenAPI 文档 JSON 路由 + Swagger UI 静态资源，最内层挂载）
        if (options.enableSimApiDoc) {
            logger.info("开始配置 SimApiDoc...")
            // 归一化路由前缀：去掉首尾斜杠，保证形如 "docs"
            let rawPrefix = options.simApiDocOptions.urlPrefix.trim().trimStart('/').trimEnd('/')
            let prefix = if (rawPrefix.isEmpty()) { "docs" } else { rawPrefix }
            let routeBase = "/${prefix}"
            // 文档列表端点：供 Swagger UI 下拉切换多文档（[{name, url}]）
            host.mapGet("${routeBase}/urls", { context =>
                let simOptions = context.services.getOrThrow<SimApiOptions>()
                let groups = simOptions.simApiDocOptions.distinctGroups()
                let sb = StringBuilder()
                sb.append("[")
                for (i in 0..groups.size) {
                    if (i > 0) {
                        sb.append(",")
                    }
                    let g = groups[i]
                    let name = g.name.replace("\"", "\\\"")
                    sb.append("{\"name\":\"${name}\",\"url\":\"${routeBase}/${g.id}.json\"}")
                }
                sb.append("]")
                context.response.contentType = "application/json; charset=utf-8"
                context.response.write(sb.toString())
            }).withOpenApi(SimApiDoc(ignore: true))
            host.mapOpenApi("${routeBase}/{documentName}.json")
            host.useOpenApiUI()
        }
    }

    // ===== 私有辅助 =====

    private static func addSimApiCore(builder: WebHostBuilder, options: SimApiOptions): WebHostBuilder {
        // 注册单例配置
        builder.services.addSingleton<SimApiOptions>(options)
        // 子配置不单独注册：中间件统一注入 SimApiOptions 后访问其属性


        // 自定义日志格式（替换默认 console provider）
        if (options.enableLogger) {
            builder.services.addLogging {
                logging =>
                    logging.clearProviders()
                    logging.addProvider(SimApiLoggerProvider())
            }
        }

        // 中间件无需注册：挂载时由 ActivatorUtilities 从 DI 解析构造参数创建


        // API 文档（OpenAPI）：按 SimApiDocOptions.apiGroups 注册多个文档
        // （如 api/admin 各生成 /{urlPrefix}/{id}.json）；未标注 groupNames 的接口仅进入默认组文档
        if (options.enableSimApiDoc) {
            let docOptions = options.simApiDocOptions
            let groups = docOptions.distinctGroups()
            if (groups.isEmpty()) {
                builder.services.addOpenApi() {opt =>
                    opt.includeUnGrouped = true
                }
            } else {
                var defaultId: ?String = None
                for (group in groups) {
                    if (group.isDefault) {
                        defaultId = Some(group.id)
                        break
                    }
                }
                if (let None <- defaultId) {
                    defaultId = Some(groups[0].id)
                }
                let defId = match (defaultId) {
                    case Some(id) => id
                    case None => ""
                }
                for (group in groups) {
                    let gid = group.id
                    let include = (gid == defId)
                    builder.services.addOpenApi(gid) {opt =>
                        opt.includeUnGrouped = include
                    }
                }
            }
        }

        // 认证（DI 自动注入 SimApiOptions）
        if (options.enableSimApiAuth) {
            builder.services.addSingleton<SimApiAuth, SimApiAuth>()
        }

        // SimApiAuthChecker 自动扫描注册
        // 扫描调用者包中的实现类，按【接口】注册；执行时用 getAll<SimApiAuthChecker>() 一次解析全部实现，
        // 无需在 SimApiOptions 里维护类型列表。
        if (options.enableSimApiAuth) {
            let checkers = SimApiControllerScanner.scanAuthCheckers()
            for (checkerType in checkers) {
                builder.services.addScoped(TypeInfo.of<SimApiAuthChecker>(), checkerType)
            }
        }

        // 缓存（DI 自动注入 SimApiOptions）
        if (options.enableSimApiCache) {
            builder.services.addSingleton<SimApiCache, SimApiCache>()
        }

        // HTTP 客户端（DI 自动注入 SimApiOptions）
        if (options.enableSimApiHttpClient) {
            builder.services.addSingleton<SimApiHttpClient, SimApiHttpClient>()
        }

        // 存储（S3/MinIO）：
        // 仓颉版注册为 Scoped 以便注入 IHttpContextAccessor（DI 禁止 singleton 消费 scoped），
        // 桶初始化由静态守卫保证只执行一次。
        if (options.enableSimApiStorage) {
            builder.services.addHttpContextAccessor()
            builder.services.addScoped<SimApiStorage, SimApiStorage>()
        }

        // AuthGate 认证中心 SDK
        if (options.enableSimApiAuthGate) {
            builder.services.addSingleton<SimApiAuthClient, SimApiAuthClient>()
            builder.services.addSingleton<SimApiAuthCenter, SimApiAuthCenter>()
            builder.services.addSingleton<SimApiAuthIam, SimApiAuthIam>()
        }

        // CORS
        if (options.enableCors) {
            builder.services.addCors {
                cors =>
                    cors.addDefaultPolicy {
                        policy =>
                            policy.allowAnyOrigin()
                            policy.allowAnyMethod()
                            policy.allowAnyHeader()
                    }
            }
        }

        return builder
    }

    /// 注册 MVC 服务，并注册 SimApi 内置控制器 + 用户控制器到 ApplicationPartManager。
    private static func addControllers(services: ServiceCollection, controllerTypes: Array<TypeInfo>): MvcBuilder {
        // 调用 soulsoft_web_mvc 的无参 addControllers() 注册 MVC 核心服务
        let mvc = services.addControllers()
        let types = ArrayList<TypeInfo>()
        // SimApi 内置控制器
        types.add(TypeInfo.of<SimApiCommonController>())
        types.add(TypeInfo.of<SimApiAuthController>())
        // 用户控制器
        for (t in controllerTypes) {
            types.add(t)
        }
        let part = AssemblyPart("simcu::simapi.controllers", types.toArray())
        mvc.addApplicationPart(part)
        mvc
    }
}
