import * as v from "valibot";

import "dotenv/config";

/**
 * Settings schema using Valibot for validation
 */
export const settingsSchema = v.object({
    appName: v.string(),
    nodeEnv: v.string(),
    logLevel: v.string(),

    isDevelopment: v.optional(v.boolean()),

    redisUrl: v.string(),
    databaseUrl: v.string(),

    internalApiKey: v.string(),
    debugKey: v.string(),

    orchestratorApiUrl: v.string(),
    publicWsScrcpySvcUrl: v.string(),
    publicFrontendUrl: v.string(),

    betterAuthUrl: v.string(),
    betterAuthSecret: v.string(),

    twoFaSecret: v.string(),
    twofaSessionExpiryMinutes: v.optional(v.number()),
    twofaRequiredHours: v.optional(v.number()),

    defaultAdminEmail: v.string(),
    defaultAdminPassword: v.string(),

    otelServiceName: v.string(),
    otelExporterOtlpHttpEndpoint: v.string(),
});

export type Settings = v.InferOutput<typeof settingsSchema>;

/**
 * Helper to get environment variable with default value
 */
function getEnv(key: string, defaultValue: string = ""): string {
    return process.env[key] ?? defaultValue;
}

/**
 * Helper to get environment variable as number with default value
 */
function getEnvNumber(key: string, defaultValue: number): number {
    const value = process.env[key];
    if (!value) return defaultValue;
    const parsed = Number(value);
    return Number.isNaN(parsed) ? defaultValue : parsed;
}

/**
 * Parse comma-separated string into array
 */
function parseCommaSeparated(value: string): string[] {
    return value
        .split(",")
        .map((item) => item.trim())
        .filter((item) => item.length > 0);
}

/**
 * Load and validate settings from environment variables
 */
function loadSettings(): Settings {
    const nodeEnv = getEnv("NODE_ENV", "development");

    const rawSettings = {
        appName: getEnv("APP_NAME", "App"),
        nodeEnv,
        logLevel: getEnv("LOG_LEVEL", "info"),

        isDevelopment: nodeEnv === "development",

        redisUrl: getEnv("REDIS_URL", "redis://localhost:6379"),
        databaseUrl: getEnv("DATABASE_URL"),

        internalApiKey: getEnv("INTERNAL_API_KEY"),
        debugKey: getEnv("DEBUG_KEY"),

        orchestratorApiUrl: getEnv(
            "ORCHESTRATOR_API_URL",
            "http://localhost:3000",
        ),
        publicWsScrcpySvcUrl: getEnv("PUBLIC_WS_SCRCPY_SVC_URL"),
        publicFrontendUrl: getEnv("PUBLIC_FRONTEND_URL"),

        betterAuthUrl: getEnv("BETTER_AUTH_URL"),
        betterAuthSecret: getEnv("BETTER_AUTH_SECRET"),

        twoFaSecret: getEnv("TWOFA_SECRET"),
        twofaSessionExpiryMinutes: getEnvNumber(
            "TWOFA_SESSION_EXPIRY_MINUTES",
            10,
        ),
        twofaRequiredHours: getEnvNumber("TWOFA_REQUIRED_HOURS", 24),

        defaultAdminEmail: getEnv("DEFAULT_ADMIN_EMAIL"),
        defaultAdminPassword: getEnv("DEFAULT_ADMIN_PASSWORD"),

        otelServiceName: getEnv("OTEL_SERVICE_NAME"),
        otelExporterOtlpHttpEndpoint: getEnv(
            "OTEL_EXPORTER_OTLP_HTTP_ENDPOINT",
        ),
    };

    try {
        return v.parse(settingsSchema, rawSettings);
    } catch (error) {
        console.error("❌ Settings validation failed:");
        if (error instanceof v.ValiError) {
            for (const issue of error.issues) {
                console.error(
                    `  - ${issue.path?.map((p: any) => p.key).join(".")}: ${issue.message}`,
                );
            }
        } else {
            console.error(error);
        }
        throw new Error(
            "Failed to load settings. Check environment variables.",
        );
    }
}

export const settings = loadSettings();

export const getSetting = <K extends keyof Settings>(key: K): Settings[K] => {
    return settings[key];
};

console.log(`✅ Settings loaded | ${settings.appName} (${settings.nodeEnv})`);
