import { config as dotenv } from 'dotenv';
import zod from 'zod';
// Prefer isolated test env file when provided, otherwise fall back to repo-level .env
dotenv({
    path: process.env.TEST_ENV_FILE && process.env.TEST_ENV_FILE.trim() !== ''
        ? process.env.TEST_ENV_FILE
        : ['.env', '../../.env'],
    debug: process.env.RELEASE ? false : true,
});
const isNumberString = (input) => zod.string().regex(/^\d+$/).safeParse(input).success;
const numberFromNumberOrNumberString = (input) => {
    if (typeof input === 'number')
        return input;
    if (isNumberString(input))
        return Number(input);
    return undefined;
};
const NumberFromString = zod.preprocess(numberFromNumberOrNumberString, zod.number().min(1));
// treat an empty string (`''`) as undefined
const emptyString = (input) => {
    return zod.preprocess((value) => {
        if (value === '')
            return undefined;
        return value;
    }, input);
};
const PostgresModel = zod.object({
    POSTGRES_SSL: emptyString(zod.union([zod.literal('1'), zod.literal('0')]).optional()),
    POSTGRES_HOST: zod.string(),
    POSTGRES_PORT: NumberFromString,
    POSTGRES_DB: zod.string(),
    POSTGRES_USER: zod.string(),
    POSTGRES_PASSWORD: zod.string(),
    POSTGRES_MAX_CLIENTS: emptyString(NumberFromString).optional().default(20),
});
const CloudinaryModel = zod.union([
    zod
        .object({
        CLOUDINARY_NAME: zod.string().optional(),
        CLOUDINARY_API_KEY: zod.string().optional(),
        CLOUDINARY_API_SECRET: zod.string().optional(),
    })
        .superRefine((data, ctx) => {
        if (!!data.CLOUDINARY_NAME !== !!data.CLOUDINARY_API_KEY ||
            !!data.CLOUDINARY_NAME !== !!data.CLOUDINARY_API_SECRET) {
            ctx.addIssue({
                code: 'custom',
                message: 'CLOUDINARY_NAME, CLOUDINARY_API_KEY, and CLOUDINARY_API_SECRET must be provided together.',
            });
        }
    }),
    zod.void(),
]);
const HiveModel = zod.union([
    zod.object({
        HIVE_TOKEN: zod.string().optional(),
    }),
    zod.void(),
]);
const GoogleDriveModel = zod.union([
    zod.object({
        GOOGLE_DRIVE_API_KEY: zod.string().optional(),
    }),
    zod.void(),
]);
const CredentialsModel = zod.object({
    CREDENTIALS_ENCRYPTION_KEY: zod
        .string()
        .trim()
        .regex(/^[a-f0-9]{64}$/i),
});
const GeneralModel = zod.object({
    FRONTEND_URL: zod.url().optional(),
});
const OtelModel = zod
    .object({
    OTEL_ENABLED: emptyString(zod
        .union([zod.literal('1'), zod.literal('0')])
        .optional()
        .default('0')),
    OTEL_SERVICE_NAME: emptyString(zod.string().optional().default('accounter-server')),
    OTEL_SERVICE_NAMESPACE: emptyString(zod.string().optional().default('accounter')),
    OTEL_DEPLOYMENT_ENV: emptyString(zod
        .string()
        .optional()
        .default(process.env.NODE_ENV ?? 'development')),
    OTEL_EXPORTER_OTLP_ENDPOINT: emptyString(zod.string().optional()),
    OTEL_EXPORTER_OTLP_HEADERS: emptyString(zod.string().optional()),
    OTEL_TRACES_SAMPLER: emptyString(zod
        .enum([
        'parentbased_traceidratio',
        'always_on',
        'always_off',
        'traceidratio',
        'parentbased_always_on',
        'parentbased_always_off',
    ])
        .optional()
        .default('always_on')),
    OTEL_TRACES_SAMPLER_ARG: emptyString(zod.string().optional()),
    OTEL_STARTUP_STRICT: emptyString(zod.union([zod.literal('true'), zod.literal('false')]).optional()),
})
    .superRefine((data, ctx) => {
    if (data.OTEL_ENABLED === '1' && !data.OTEL_EXPORTER_OTLP_ENDPOINT) {
        ctx.addIssue({
            code: 'custom',
            path: ['OTEL_EXPORTER_OTLP_ENDPOINT'],
            message: 'OTEL_EXPORTER_OTLP_ENDPOINT is required when OTEL_ENABLED is "1".',
        });
    }
    const usesRatioSampler = data.OTEL_TRACES_SAMPLER === 'parentbased_traceidratio' ||
        data.OTEL_TRACES_SAMPLER === 'traceidratio';
    if (usesRatioSampler) {
        if (data.OTEL_TRACES_SAMPLER_ARG === undefined) {
            ctx.addIssue({
                code: 'custom',
                path: ['OTEL_TRACES_SAMPLER_ARG'],
                message: 'OTEL_TRACES_SAMPLER_ARG is required when OTEL_TRACES_SAMPLER is a ratio sampler ("traceidratio" or "parentbased_traceidratio").',
            });
        }
        else {
            const num = Number(data.OTEL_TRACES_SAMPLER_ARG);
            if (!Number.isFinite(num) || num < 0 || num > 1) {
                ctx.addIssue({
                    code: 'custom',
                    path: ['OTEL_TRACES_SAMPLER_ARG'],
                    message: 'OTEL_TRACES_SAMPLER_ARG must be a numeric string between 0 and 1.',
                });
            }
        }
    }
});
const GatewayControlPlaneModel = zod.object({
    GATEWAY_CP_TOKEN: emptyString(zod.string().optional()),
});
const EmailIngestionModel = zod.object({
    EMAIL_INGESTION_V2_ENABLED: emptyString(zod
        .union([zod.literal('1'), zod.literal('0')])
        .optional()
        .default('0')),
    EMAIL_INGESTION_SHADOW_MODE: emptyString(zod
        .union([zod.literal('1'), zod.literal('0')])
        .optional()
        .default('0')),
});
const Auth0Model = zod.union([
    zod.object({
        AUTH0_DOMAIN: zod.string().min(1),
        AUTH0_AUDIENCE: zod.string().min(1),
        AUTH0_CLIENT_ID: zod.string().min(1),
        AUTH0_CLIENT_SECRET: zod.string().min(1),
        AUTH0_MANAGEMENT_AUDIENCE: zod.string().min(1),
    }),
    // If no Auth0 variables are provided, validation passes (optional configuration)
    // We use a looser object check here because process.env is always an object
    zod
        .object({
        AUTH0_DOMAIN: zod.literal('').optional(),
        AUTH0_AUDIENCE: zod.literal('').optional(),
        AUTH0_CLIENT_ID: zod.literal('').optional(),
        AUTH0_CLIENT_SECRET: zod.literal('').optional(),
        AUTH0_MANAGEMENT_AUDIENCE: zod.literal('').optional(),
    })
        .transform(() => undefined),
]);
const configs = {
    postgres: PostgresModel.safeParse(process.env),
    cloudinary: CloudinaryModel.safeParse(process.env),
    hive: HiveModel.safeParse(process.env),
    googleDrive: GoogleDriveModel.safeParse(process.env),
    auth0: Auth0Model.safeParse(process.env),
    credentials: CredentialsModel.safeParse(process.env),
    general: GeneralModel.safeParse(process.env),
    otel: OtelModel.safeParse(process.env),
    emailIngestion: EmailIngestionModel.safeParse(process.env),
    gatewayControlPlane: GatewayControlPlaneModel.safeParse(process.env),
};
const environmentErrors = [];
for (const config of Object.values(configs)) {
    if (config.success === false) {
        environmentErrors.push(JSON.stringify(config.error.format(), null, 4));
    }
}
if (environmentErrors.length) {
    const fullError = environmentErrors.join(`\n`);
    console.error('❌ Invalid environment variables:', fullError);
    process.exit(1);
}
function extractConfig(config) {
    if (!config.success) {
        throw new Error('Something went wrong.');
    }
    return config.data;
}
const postgres = extractConfig(configs.postgres);
const cloudinary = extractConfig(configs.cloudinary);
const hive = extractConfig(configs.hive);
const googleDrive = extractConfig(configs.googleDrive);
const auth0 = extractConfig(configs.auth0);
const credentials = extractConfig(configs.credentials);
const general = extractConfig(configs.general);
const otel = extractConfig(configs.otel);
const emailIngestion = extractConfig(configs.emailIngestion);
const gatewayControlPlane = extractConfig(configs.gatewayControlPlane);
export const env = {
    postgres: {
        host: postgres.POSTGRES_HOST,
        port: postgres.POSTGRES_PORT,
        db: postgres.POSTGRES_DB,
        user: postgres.POSTGRES_USER,
        password: postgres.POSTGRES_PASSWORD,
        ssl: postgres.POSTGRES_SSL === '1',
        max: postgres.POSTGRES_MAX_CLIENTS,
    },
    cloudinary: cloudinary?.CLOUDINARY_API_KEY
        ? {
            name: cloudinary.CLOUDINARY_NAME,
            apiKey: cloudinary.CLOUDINARY_API_KEY,
            apiSecret: cloudinary.CLOUDINARY_API_SECRET,
        }
        : undefined,
    hive: hive?.HIVE_TOKEN
        ? {
            hiveToken: hive.HIVE_TOKEN,
        }
        : undefined,
    googleDrive: googleDrive?.GOOGLE_DRIVE_API_KEY
        ? {
            driveApiKey: googleDrive.GOOGLE_DRIVE_API_KEY,
        }
        : undefined,
    credentialsEncryptionKey: credentials.CREDENTIALS_ENCRYPTION_KEY,
    auth0: auth0
        ? {
            domain: auth0.AUTH0_DOMAIN,
            audience: auth0.AUTH0_AUDIENCE,
            clientId: auth0.AUTH0_CLIENT_ID,
            clientSecret: auth0.AUTH0_CLIENT_SECRET,
            managementAudience: auth0.AUTH0_MANAGEMENT_AUDIENCE,
        }
        : undefined,
    general: {
        frontendUrl: general?.FRONTEND_URL,
    },
    otel: {
        enabled: otel.OTEL_ENABLED === '1',
        serviceName: otel.OTEL_SERVICE_NAME,
        serviceNamespace: otel.OTEL_SERVICE_NAMESPACE,
        deploymentEnv: otel.OTEL_DEPLOYMENT_ENV,
        exporterEndpoint: otel.OTEL_EXPORTER_OTLP_ENDPOINT,
        exporterHeaders: otel.OTEL_EXPORTER_OTLP_HEADERS,
        tracesSampler: otel.OTEL_TRACES_SAMPLER,
        tracesSamplerArg: (otel.OTEL_TRACES_SAMPLER === 'parentbased_traceidratio' ||
            otel.OTEL_TRACES_SAMPLER === 'traceidratio') &&
            otel.OTEL_TRACES_SAMPLER_ARG !== undefined
            ? Number(otel.OTEL_TRACES_SAMPLER_ARG)
            : undefined,
        startupStrict: otel.OTEL_STARTUP_STRICT === 'true',
    },
    emailIngestion: {
        v2Enabled: emailIngestion.EMAIL_INGESTION_V2_ENABLED === '1',
        shadowMode: emailIngestion.EMAIL_INGESTION_SHADOW_MODE === '1',
    },
    gatewayControlPlane: {
        token: gatewayControlPlane.GATEWAY_CP_TOKEN,
    },
};
//# sourceMappingURL=environment.js.map