package top.r3944realms.ltdmanager.module

import top.r3944realms.ltdmanager.GlobalManager
import top.r3944realms.ltdmanager.core.config.ModuleConfig
import top.r3944realms.ltdmanager.core.config.ModuleConfig.Module.ModuleType.*
import top.r3944realms.ltdmanager.core.config.YamlConfigLoader
import top.r3944realms.ltdmanager.module.exception.ConfigError
import top.r3944realms.ltdmanager.module.gitea.GiteaEventType
import top.r3944realms.ltdmanager.module.gitea.GiteaWebhookModule
import top.r3944realms.ltdmanager.module.RconCommandModule
import top.r3944realms.ltdmanager.module.WhitelistAuditModule

object ModuleFactory {
    fun createModule(config: ModuleConfig.Module): BaseModule {
        return when(config.type) {
            GROUP_MESSAGE_POLLING_MODULE -> createGroupMessagePolling(config)
            GROUP_REQUEST_HANDLER_MODULE -> createGroupRequestHandler(config)
            MAIL_MODULE -> createMail(config)
            BAN_MODULE -> createBan(config)
            DG_LAB_MODULE -> createDgLab(config)
            INVITE_MODULE -> createInvite(config)
            MC_SERVER_STATUS_MODULE -> createMcServerStatus(config)
            RCON_PLAYER_LIST_MODULE -> createRconPlayerList(config)
            STATE_MODULE -> createState(config)
            MOD_GROUP_HANDLER_MODULE -> createModGroupHandler(config)
            HELP_MODULE -> createHelpModule(config)
            GITEA_WEBHOOK_MODULE -> createGiteaWebhook(config)
            RCON_COMMAND_MODULE -> createRconCommand(config)
            WHITELIST_AUDIT_MODULE -> createWhitelistAudit(config)
            UNKNOWN_MODULE -> throw ConfigError(ConfigError.Type.INVALID_PARAMETER, "unknown module")
        }
    }
    private fun resolveDependency(dep: ModuleConfig.Module.Dependency?, name: String): BaseModule {
        if (dep == null) {
            throw ConfigError(ConfigError.Type.MISSING_PARAMETER, "dependency", name)
        }
        val depName = dep.getDepName()
        return GlobalManager.moduleManager.getModule(depName)
            ?: throw ConfigError(
                ConfigError.Type.OTHER,
                "resolveDependency",
                "依赖模块 '$depName' 未注册 — 请检查 name/type 是否匹配且目标模块定义在 WHITELIST_AUDIT_MODULE 之前"
            )
    }
    private fun createGroupMessagePolling(config: ModuleConfig.Module): GroupMessagePollingModule {
        val targetGroupId = config.long("target-group-id")
        val pollIntervalMillis = config.getOrDefault("poll-interval-millis", 5_000L)
        val msgHistoryCheck = config.getOrDefault("msg-history-check", 15)
        return GroupMessagePollingModule(
            config.name, targetGroupId,
            pollIntervalMillis, msgHistoryCheck,
        )
    }
    private fun createGroupRequestHandler(config: ModuleConfig.Module): GroupRequestHandlerModule {
        val targetGroupId = config.long("target-group-id")
        val pollIntervalMillis = config.getOrDefault("poll-interval-millis", 30_000L)
        return GroupRequestHandlerModule(
            config.name, GlobalManager.napCatClient,
            targetGroupId, pollIntervalMillis
        )
    }

    private fun createMail(config: ModuleConfig.Module): MailModule {
        val mailConfig = YamlConfigLoader.loadMailConfig()
        return MailModule(
            moduleName = config.name,
            host = mailConfig.host.toString(),
            authToken = mailConfig.decryptedPassword.toString(),
            port = mailConfig.port!!,
            senderEmailAddress = mailConfig.mailAddress!!
        )
    }

    private fun createBan(config: ModuleConfig.Module): BanModule {
        val selfId = config.long("self-id")
        val adminIds = config.list<Long>("admin-ids")
        val muteCommandPrefixList = config.stringList("mute-command-prefix-list")
        val unmuteCommandPrefixList = config.stringList("unmute-command-prefix-list")
        val groupMessagePollingModule = resolveDependency(config.findDependency(GROUP_MESSAGE_POLLING_MODULE), "groupMessagePolling") as GroupMessagePollingModule
        val minBanMinutes = config.int("min-ban-minutes")
        val maxBanMinutes = config.int("max-ban-minutes")
        val factorX: Int = config.int("factor-x")
        return BanModule(
            config.name,
            groupMessagePollingModule,
            selfId,
            adminIds,
            muteCommandPrefixList,
            unmuteCommandPrefixList,
            minBanMinutes,
            maxBanMinutes,
            factorX
        )
    }

    private fun createDgLab(config: ModuleConfig.Module): DGLabModule {
        val selfId = config.long("self-id")
        val adminIds = config.list<Long>("admin-ids")
        val maxClientNumber = config.int("max-client-number")
        val commandHead = config.stringList("command-head")
        val groupMessagePollingModule = resolveDependency(config.findDependency(GROUP_MESSAGE_POLLING_MODULE), "groupMessagePolling") as GroupMessagePollingModule
        return DGLabModule(
            config.name,
            groupMessagePollingModule,
            selfId,
            adminIds,
            maxClientNumber,
            commandHead
        )
    }

    private fun createInvite(config: ModuleConfig.Module): InvitationCodesModule {
        val selfId = config.long("self-id")
        val groupMessagePollingModule = resolveDependency(config.findDependency(GROUP_MESSAGE_POLLING_MODULE), "groupMessagePolling") as GroupMessagePollingModule
        val mailModule = resolveDependency(config.findDependency(MAIL_MODULE), "mailModule") as MailModule
        val blessingSkinConfig = YamlConfigLoader.loadBlessingSkinServerConfig()
        val cooldownMillis = config.getOrDefault("cooldown-millis", 120_000L)
        val keywords = config.stringList("keywords")
        return InvitationCodesModule(
            config.name,
            groupMessagePollingModule,
            mailModule,
            blessingSkinConfig.invitationApi?.decryptedToken!!,
            selfId,
            cooldownMillis,
            keywords.toSet()
        )
    }

    private fun createMcServerStatus(config: ModuleConfig.Module): McServerStatusModule {
        val selfId = config.long("self-id")
        val cooldownMillis = config.getOrDefault("cooldown-millis", 60_000L)
        val groupMessagePollingModule = resolveDependency(config.findDependency(GROUP_MESSAGE_POLLING_MODULE), "groupMessagePolling") as GroupMessagePollingModule
        val commands = config.stringList("commands")
        val selfNickName = config.string("self-nick-name")
        val preset = config.map<Set<String>, String>("preset-server")
        return McServerStatusModule(
            config.name,
            groupMessagePollingModule,
            selfId,
            selfNickName,
            cooldownMillis,
            commands,
            preset
        )
    }

    private fun createRconPlayerList(config: ModuleConfig.Module): RconPlayerListModule {
        val toolConfig = YamlConfigLoader.loadToolConfig()
        val selfId = config.long("self-id")
        val cooldownMillis = config.getOrDefault("cooldown-millis", 10_000L)
        val rconTimeout = config.getOrDefault("rcon-timeout-millis", 2_000L)
        val groupMessagePollingModule = resolveDependency(config.findDependency(GROUP_MESSAGE_POLLING_MODULE), "groupMessagePolling") as GroupMessagePollingModule
        val selfNickName = config.string("self-nick-name")
        val keywords = config.stringList("keywords")
        val enableBasePath = toolConfig.rcon.enableBasePath ?: false
        var rconToolPath = toolConfig.rcon.mcRconToolPath.toString()
        var rconConfigPath = toolConfig.rcon.mcRconToolConfigPath.toString()
        if (enableBasePath) {
            rconToolPath += config.string("rcon-tool-path")
            rconConfigPath += config.string("rcon-config-path")
        }
        return RconPlayerListModule(
            config.name,
            groupMessagePollingModule,
            rconTimeout,
            cooldownMillis,
            selfId,
            selfNickName,
            rconToolPath,
            rconConfigPath,
            keywords.toSet()
        )
    }

    private fun createState(config: ModuleConfig.Module): StateModule {
        val onlineName = config.string("online-name")
        val offlineName = config.string("offline-name")
        return StateModule(
            config.name,
            onlineName,
            offlineName
        )
    }

    private fun createModGroupHandler(config: ModuleConfig.Module): ModGroupHandlerModule {
        val targetGroupId = config.long("target-group-id")
        val answers = config.stringList("answers")
        val pollingMillis = config.getOrDefault("poll-interval-millis", 30_000L)
        return ModGroupHandlerModule(
            config.name,
            targetGroupId,
            answers,
            pollingMillis
        )
    }

    private fun createHelpModule(config: ModuleConfig.Module): HelpModule {
        val selfId = config.long("self-id")
        val cooldownMillis = config.getOrDefault("cooldown-millis", 10_000L)
        val groupMessagePollingModule = resolveDependency(config.findDependency(GROUP_MESSAGE_POLLING_MODULE), "groupMessagePolling") as GroupMessagePollingModule
        val selfNickName = config.string("self-nick-name")
        val keywords = config.stringList("keywords")
        return HelpModule(
            config.name,
            groupMessagePollingModule,
            selfId,
            selfNickName,
            keywords,
            cooldownMillis
        )
    }

    private fun createGiteaWebhook(config: ModuleConfig.Module): GiteaWebhookModule {
        val port = config.int("webhook-port")
        val webhookPath = config.getOrDefault("webhook-path", "/gitea-webhook")
        val secret = config.getOrDefault("webhook-secret", "")
        val targetGroupId = config.long("target-group-id")
        val eventNames = config.getOrDefault("events", emptyList<String>())
        val enabledEvents = if (eventNames.isEmpty()) {
            GiteaEventType.entries.toSet()
        } else {
            eventNames.mapNotNull { GiteaEventType.fromHeader(it) }.toSet()
        }
        return GiteaWebhookModule(
            config.name,
            port,
            webhookPath,
            secret,
            targetGroupId,
            enabledEvents
        )
    }

    private fun createRconCommand(config: ModuleConfig.Module): RconCommandModule {
        val toolConfig = YamlConfigLoader.loadToolConfig()
        val selfId = config.long("self-id")
        val selfNickName = config.string("self-nick-name")
        val allowedUsers = config.list<Long>("admin-ids").toSet()
        val commandBlocklist = config.stringList("command-blocklist").toSet()
        val commandPrefix = config.string("command-prefix")
        val rconTimeoutSec = config.getOrDefault("rcon-timeout-sec", 5L)
        val enableBasePath = toolConfig.rcon.enableBasePath ?: false
        var rconToolPath = toolConfig.rcon.mcRconToolPath.toString()
        var rconConfigPath = toolConfig.rcon.mcRconToolConfigPath.toString()
        if (enableBasePath) {
            rconToolPath += config.string("rcon-tool-path")
            rconConfigPath += config.string("rcon-config-path")
        }
        val groupMessagePollingModule = resolveDependency(
            config.findDependency(GROUP_MESSAGE_POLLING_MODULE), "groupMessagePolling"
        ) as GroupMessagePollingModule
        return RconCommandModule(
            config.name,
            groupMessagePollingModule,
            rconToolPath,
            rconConfigPath,
            rconTimeoutSec,
            selfId,
            selfNickName,
            allowedUsers,
            commandBlocklist,
            commandPrefix
        )
    }

    private fun createWhitelistAudit(config: ModuleConfig.Module): WhitelistAuditModule {
        val filterQqList = config.list<Long>("filter-qq-list").toSet()
        val auditAllowedUsers = config.list<Long>("audit-allowed-ids").toSet()
        val enableEmail = config.getOrDefault("enable-email", false)
        val reActivationKeywords = config.stringList("re-activation-keywords").toSet()
        val auditCommandPrefix = config.getOrDefault("audit-command-prefix", "审计")
        val gracePeriodDays = config.int("grace-period-days")
        val expiryWarningDays = config.int("expiry-warning-days")
        val pollIntervalMinutes = config.getOrDefault("poll-interval-minutes", 60L)
        val selfId = config.long("self-id")
        val groupMessagePollingModule = resolveDependency(
            config.findDependency(GROUP_MESSAGE_POLLING_MODULE), "groupMessagePolling"
        ) as GroupMessagePollingModule
        // 第二依赖：白名单群轮询模块（通过依赖名区分）
        val whitelistGroupPollingName = config.getOrDefault("whitelist-group-polling-dep-name", "")
        val whitelistGroupPollingModule = if (whitelistGroupPollingName.isNotEmpty()) {
            resolveDependency(
                config.dependencies?.find { it.name == whitelistGroupPollingName && it.type == GROUP_MESSAGE_POLLING_MODULE },
                "whitelistGroupPolling"
            ) as GroupMessagePollingModule
        } else {
            groupMessagePollingModule
        }
        val mailModule = if (enableEmail) {
            resolveDependency(config.findDependency(MAIL_MODULE), "mailModule") as MailModule
        } else null
        return WhitelistAuditModule(
            config.name,
            groupMessagePollingModule,
            whitelistGroupPollingModule,
            GlobalManager.whitelistSystemClient,
            mailModule,
            filterQqList,
            auditAllowedUsers,
            reActivationKeywords,
            auditCommandPrefix,
            gracePeriodDays,
            expiryWarningDays,
            pollIntervalMinutes,
            selfId
        )
    }

}