/**
 * @fileoverview Bot settings endpoints for Aurora API.
 * Provides endpoints for reading and updating bot configuration,
 * as well as fetching Discord metadata.
 */

import type { RouteContext, RouteModule } from "./types";
import { jsonResponse, errorResponse, withErrorHandling } from "./utils";

/**
 * JSON replacer for BigInt serialization.
 */
function jsonReplacer(_key: string, value: unknown): unknown {
    return typeof value === "bigint" ? value.toString() : value;
}

/**
 * Settings routes handler.
 * 
 * Endpoints:
 * - GET /api/settings - Get current bot configuration
 * - POST /api/settings - Update bot configuration (partial merge)
 * - GET /api/settings/meta - Get Discord metadata (roles, channels, commands)
 */
async function handler(ctx: RouteContext): Promise<Response | null> {
    const { pathname, method, req } = ctx;

    // Only handle requests to /api/settings*
    if (!pathname.startsWith("/api/settings")) {
        return null;
    }

    /**
     * @route GET /api/settings
     * @description Returns the current bot configuration.
     * Configuration includes economy settings, leveling settings,
     * command toggles, and other system settings.
     * @response 200 - Full configuration object
     * @response 500 - Error fetching settings
     * 
     * @example
     * // Response
     * {
     *   "economy": { "dailyReward": 100, "streakBonus": 10 },
     *   "leveling": { "xpPerMessage": 15, "levelUpChannel": "123456789" },
     *   "commands": { "disabled": [], "channelLocks": {} }
     * }
     */
    if (pathname === "/api/settings" && method === "GET") {
        return withErrorHandling(async () => {
            const { config } = await import("@shared/lib/config");
            return new Response(JSON.stringify(config, jsonReplacer), {
                headers: { "Content-Type": "application/json" }
            });
        }, "fetch settings");
    }

    /**
     * @route POST /api/settings
     * @description Updates bot configuration with partial merge.
     * Only the provided fields will be updated; other settings remain unchanged.
     * After updating, commands are automatically reloaded.
     * 
     * @body Partial configuration object
     * @response 200 - `{ success: true }`
     * @response 400 - Validation error
     * @response 500 - Error saving settings
     * 
     * @example
     * // Request - Only update economy daily reward
     * POST /api/settings
     * { "economy": { "dailyReward": 150 } }
     */
    if (pathname === "/api/settings" && method === "POST") {
        try {
            const partialConfig = await req.json();
            const { saveConfig, config: currentConfig } = await import("@shared/lib/config");
            const { deepMerge } = await import("@shared/lib/utils");

            // Merge partial update into current config
            const mergedConfig = deepMerge(currentConfig, partialConfig);

            // saveConfig throws if validation fails
            saveConfig(mergedConfig);

            const { systemEvents, EVENTS } = await import("@shared/lib/events");
            systemEvents.emit(EVENTS.ACTIONS.RELOAD_COMMANDS);

            return jsonResponse({ success: true });
        } catch (error) {
            // Return 400 for validation errors
            const message = error instanceof Error ? error.message : String(error);
            return errorResponse("Failed to save settings", 400, message);
        }
    }

    /**
     * @route GET /api/settings/meta
     * @description Returns Discord server metadata for settings UI.
     * Provides lists of roles, channels, and registered commands.
     * 
     * @response 200 - `{ roles: Role[], channels: Channel[], commands: Command[] }`
     * @response 500 - Error fetching metadata
     * 
     * @example
     * // Response
     * {
     *   "roles": [
     *     { "id": "123456789", "name": "Admin", "color": "#FF0000" }
     *   ],
     *   "channels": [
     *     { "id": "987654321", "name": "general", "type": 0 }
     *   ],
     *   "commands": [
     *     { "name": "daily", "category": "economy" }
     *   ]
     * }
     */
    if (pathname === "/api/settings/meta" && method === "GET") {
        return withErrorHandling(async () => {
            const { AuroraClient } = await import("../../../bot/lib/BotClient");
            const { env } = await import("@shared/lib/env");

            if (!env.DISCORD_GUILD_ID) {
                return jsonResponse({ roles: [], channels: [], commands: [] });
            }

            const guild = AuroraClient.guilds.cache.get(env.DISCORD_GUILD_ID);
            if (!guild) {
                return jsonResponse({ roles: [], channels: [], commands: [] });
            }

            // Map roles and channels to a simplified format
            const roles = guild.roles.cache
                .sort((a, b) => b.position - a.position)
                .map(r => ({ id: r.id, name: r.name, color: r.hexColor }));

            const channels = guild.channels.cache
                .map(c => ({ id: c.id, name: c.name, type: c.type }));

            const commands = Array.from(AuroraClient.knownCommands.entries())
                .map(([name, category]) => ({ name, category }))
                .sort((a, b) => {
                    if (a.category !== b.category) return a.category.localeCompare(b.category);
                    return a.name.localeCompare(b.name);
                });

            return jsonResponse({ roles, channels, commands });
        }, "fetch settings meta");
    }

    return null;
}

export const settingsRoutes: RouteModule = {
    name: "settings",
    handler
};
