/**
 * app.config.test.ts
 *
 * Comprehensive unit tests for loadConfig() in app.config.ts.
 *
 * Strategy:
 *   - Each test saves the current process.env, mutates it, calls loadConfig(),
 *     then restores the original env. This avoids vi.resetModules() and makes
 *     every test fully isolated.
 *
 * Coverage targets:
 *   ✅ All 11 config sections and every field inside them
 *   ✅ Default values (no env vars set)
 *   ✅ Env-var overrides (custom values respected)
 *   ✅ Numeric parsing (PORT, POSTGRES_PORT, MAX_FILE_SIZE, limits …)
 *   ✅ Optional / undefined fields (s3Bucket, accessApiKey, vercelToken …)
 *   ✅ Regression: PORT default fixed from 3000 → 7130
 *   ✅ Regression: storage.appKey defaults to 'local', not 'default-app-key'
 *   ✅ PARENT_APP_KEY whitespace trimming
 *   ✅ MAX_FILE_SIZE absent → undefined (not 0 or NaN)
 *   ✅ Deployment byte limits default to 100 MiB
 */

import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { loadConfig } from '../../src/infra/config/app.config';

// ---------------------------------------------------------------------------
// Helper — save / restore process.env around each test
// ---------------------------------------------------------------------------
let savedEnv: NodeJS.ProcessEnv;

beforeEach(() => {
  savedEnv = { ...process.env };
});

afterEach(() => {
  process.env = savedEnv;
});

// ---------------------------------------------------------------------------
// Utility to wipe a set of keys so defaults kick in cleanly
// ---------------------------------------------------------------------------
function unsetEnvKeys(...keys: string[]) {
  for (const k of keys) {
    delete process.env[k];
  }
}

// ═══════════════════════════════════════════════════════════════════════════
// Section: app
// ═══════════════════════════════════════════════════════════════════════════

describe('config.app', () => {
  it('uses defaults when no env vars are set', () => {
    unsetEnvKeys('PORT', 'JWT_SECRET', 'ACCESS_API_KEY', 'LOG_LEVEL');
    const c = loadConfig();

    expect(c.app.port).toBe(7130);
    expect(c.app.jwtSecret).toBe('');
    expect(c.app.apiKey).toBe('your_api_key');
    expect(c.app.logLevel).toBe('info');
  });

  it('overrides all app fields from env', () => {
    process.env.PORT = '9000';
    process.env.JWT_SECRET = 'super-secret-jwt';
    process.env.ACCESS_API_KEY = 'ik_test1234';
    process.env.LOG_LEVEL = 'debug';
    const c = loadConfig();

    expect(c.app.port).toBe(9000);
    expect(c.app.jwtSecret).toBe('super-secret-jwt');
    expect(c.app.apiKey).toBe('ik_test1234');
    expect(c.app.logLevel).toBe('debug');
  });

  // ── PORT regression ──────────────────────────────────────────────────────
  it('REGRESSION: PORT default is 7130 (was incorrectly 3000)', () => {
    unsetEnvKeys('PORT');
    expect(loadConfig().app.port).toBe(7130);
    expect(loadConfig().app.port).not.toBe(3000);
  });

  it('parses PORT as an integer', () => {
    process.env.PORT = '8080';
    expect(loadConfig().app.port).toBe(8080);
    expect(typeof loadConfig().app.port).toBe('number');
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: telemetry
// ═══════════════════════════════════════════════════════════════════════════

describe('config.telemetry', () => {
  it('enables anonymous telemetry by default', () => {
    unsetEnvKeys(
      'INSFORGE_TELEMETRY_DISABLED',
      'INSFORGE_TELEMETRY_DEBUG',
      'INSFORGE_TELEMETRY_ENDPOINT',
      'INSFORGE_TELEMETRY_POSTHOG_API_KEY',
      'INSFORGE_TELEMETRY_INSTALLATION_ID_PATH',
      'INSFORGE_TELEMETRY_HEARTBEAT_INTERVAL_MS',
      'INSFORGE_TELEMETRY_REQUEST_TIMEOUT_MS',
      'LOGS_DIR'
    );
    const c = loadConfig();

    expect(c.telemetry).toEqual({ disabled: false });
  });

  it('only exposes the telemetry disabled env var', () => {
    process.env.INSFORGE_TELEMETRY_DISABLED = 'true';
    process.env.INSFORGE_TELEMETRY_DEBUG = '1';
    process.env.INSFORGE_TELEMETRY_ENDPOINT = 'https://events.example.com/v1';
    process.env.INSFORGE_TELEMETRY_POSTHOG_API_KEY = 'phc_custom';
    process.env.INSFORGE_TELEMETRY_INSTALLATION_ID_PATH = '/tmp/insforge-id';
    process.env.INSFORGE_TELEMETRY_HEARTBEAT_INTERVAL_MS = '60000';
    process.env.INSFORGE_TELEMETRY_REQUEST_TIMEOUT_MS = '500';
    const c = loadConfig();

    expect(c.telemetry).toEqual({ disabled: true });
  });

  it('disables telemetry with the documented opt-out value', () => {
    process.env.INSFORGE_TELEMETRY_DISABLED = '1';
    const c = loadConfig();

    expect(c.telemetry).toEqual({ disabled: true });
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: cloud
// ═══════════════════════════════════════════════════════════════════════════

describe('config.cloud', () => {
  it('uses defaults when no env vars are set', () => {
    unsetEnvKeys(
      'AWS_S3_BUCKET',
      'AWS_INSTANCE_PROFILE_NAME',
      'CLOUD_API_HOST',
      'PROJECT_ID',
      'APP_KEY',
      'AWS_CLOUDFRONT_URL',
      'AWS_CLOUDFRONT_KEY_PAIR_ID',
      'AWS_CLOUDFRONT_PRIVATE_KEY'
    );
    const c = loadConfig();

    expect(c.cloud.apiHost).toBe('https://api.insforge.dev');
    expect(c.cloud.projectId).toBeUndefined();
    expect(c.cloud.cloudFrontUrl).toBeUndefined();
    expect(c.cloud.cloudFrontKeyPairId).toBeUndefined();
    expect(c.cloud.cloudFrontPrivateKey).toBeUndefined();
  });

  it('overrides cloud fields from env', () => {
    process.env.CLOUD_API_HOST = 'https://custom.api.dev';
    process.env.PROJECT_ID = 'proj-abc123';
    process.env.AWS_CLOUDFRONT_URL = 'https://xyz.cloudfront.net';
    process.env.AWS_CLOUDFRONT_KEY_PAIR_ID = 'K1234567890';
    process.env.AWS_CLOUDFRONT_PRIVATE_KEY = 'mock-private-key-data';
    const c = loadConfig();

    expect(c.cloud.apiHost).toBe('https://custom.api.dev');
    expect(c.cloud.projectId).toBe('proj-abc123');
    expect(c.cloud.cloudFrontUrl).toBe('https://xyz.cloudfront.net');
    expect(c.cloud.cloudFrontKeyPairId).toBe('K1234567890');
    expect(c.cloud.cloudFrontPrivateKey).toBe('mock-private-key-data');
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: denoSubhosting
// ═══════════════════════════════════════════════════════════════════════════

describe('config.denoSubhosting', () => {
  it('uses empty-string defaults when tokens are absent', () => {
    unsetEnvKeys('DENO_DEPLOY_TOKEN', 'DENO_DEPLOY_ORG_ID', 'FUNCTIONS_DOMAIN');
    const c = loadConfig();

    expect(c.denoSubhosting.token).toBe('');
    expect(c.denoSubhosting.organizationId).toBe('');
    expect(c.denoSubhosting.domain).toBe('function2.insforge.app');
  });

  it('reads DENO_DEPLOY_TOKEN and DENO_DEPLOY_ORG_ID', () => {
    process.env.DENO_DEPLOY_TOKEN = 'dsh_token_test';
    process.env.DENO_DEPLOY_ORG_ID = 'org-abc';
    const c = loadConfig();

    expect(c.denoSubhosting.token).toBe('dsh_token_test');
    expect(c.denoSubhosting.organizationId).toBe('org-abc');
  });

  it('domain defaults to the v2 proxy domain and is overridable via FUNCTIONS_DOMAIN', () => {
    unsetEnvKeys('FUNCTIONS_DOMAIN');
    expect(loadConfig().denoSubhosting.domain).toBe('function2.insforge.app');

    process.env.FUNCTIONS_DOMAIN = 'custom.functions.example.com';
    expect(loadConfig().denoSubhosting.domain).toBe('custom.functions.example.com');
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: fly
// ═══════════════════════════════════════════════════════════════════════════

describe('config.fly', () => {
  it('uses empty-string defaults when tokens are absent', () => {
    unsetEnvKeys('FLY_API_TOKEN', 'FLY_ORG', 'COMPUTE_DOMAIN');
    const c = loadConfig();

    expect(c.fly.apiToken).toBe('');
    expect(c.fly.org).toBe('');
    expect(c.fly.domain).toBe('');
  });

  it('reads Fly env vars correctly', () => {
    process.env.FLY_API_TOKEN = 'fly-secret-token';
    process.env.FLY_ORG = 'my-org';
    process.env.COMPUTE_DOMAIN = 'compute.example.com';
    const c = loadConfig();

    expect(c.fly.apiToken).toBe('fly-secret-token');
    expect(c.fly.org).toBe('my-org');
    expect(c.fly.domain).toBe('compute.example.com');
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: server
// ═══════════════════════════════════════════════════════════════════════════

describe('config.server', () => {
  it('uses defaults when no env vars are set', () => {
    unsetEnvKeys(
      'MAX_JSON_BODY_SIZE',
      'MAX_URLENCODED_BODY_SIZE',
      'MAX_FILE_SIZE',
      'MAX_FILES_PER_FIELD',
      'LOGS_DIR'
    );
    const c = loadConfig();

    expect(c.server.maxJsonBodySize).toBe('100mb');
    expect(c.server.maxUrlencodedBodySize).toBe('10mb');
    expect(c.server.maxFileSize).toBeUndefined();
    expect(c.server.maxFilesPerField).toBe(10);
    expect(typeof c.server.logsDir).toBe('string');
    expect(c.server.logsDir.length).toBeGreaterThan(0);
  });

  it('overrides body size limits', () => {
    process.env.MAX_JSON_BODY_SIZE = '50mb';
    process.env.MAX_URLENCODED_BODY_SIZE = '5mb';
    const c = loadConfig();

    expect(c.server.maxJsonBodySize).toBe('50mb');
    expect(c.server.maxUrlencodedBodySize).toBe('5mb');
  });

  it('parses MAX_FILE_SIZE as number when set', () => {
    process.env.MAX_FILE_SIZE = '52428800'; // 50 MiB
    const c = loadConfig();

    expect(c.server.maxFileSize).toBe(52428800);
    expect(typeof c.server.maxFileSize).toBe('number');
  });

  it('MAX_FILE_SIZE is undefined when not set (not 0 or NaN)', () => {
    unsetEnvKeys('MAX_FILE_SIZE');
    const c = loadConfig();

    expect(c.server.maxFileSize).toBeUndefined();
    expect(c.server.maxFileSize).not.toBe(0);
    expect(c.server.maxFileSize).not.toBeNaN();
  });

  it('parses MAX_FILES_PER_FIELD as number', () => {
    process.env.MAX_FILES_PER_FIELD = '25';
    expect(loadConfig().server.maxFilesPerField).toBe(25);
  });

  it('reads LOGS_DIR when set', () => {
    process.env.LOGS_DIR = '/var/log/insforge';
    expect(loadConfig().server.logsDir).toBe('/var/log/insforge');
  });

  it('defaults trustProxy to 2 hops', () => {
    unsetEnvKeys('TRUST_PROXY');
    expect(loadConfig().server.trustProxy).toBe(2);
  });

  it('reads trustProxy as boolean true', () => {
    process.env.TRUST_PROXY = 'true';
    expect(loadConfig().server.trustProxy).toBe(true);
  });

  it('reads trustProxy as number', () => {
    process.env.TRUST_PROXY = '3';
    expect(loadConfig().server.trustProxy).toBe(3);
  });

  it('reads trustProxy as Express subnet string', () => {
    process.env.TRUST_PROXY = 'loopback, 10.0.0.0/8';
    expect(loadConfig().server.trustProxy).toBe('loopback, 10.0.0.0/8');
  });

  it('robustly falls back to defaults for 0 or negative limits', () => {
    process.env.MAX_FILES_PER_FIELD = '0';
    process.env.MAX_FILE_SIZE = '0';
    const c = loadConfig();
    expect(c.server.maxFilesPerField).toBe(10);
    expect(c.server.maxFileSize).toBeUndefined();
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: database
// ═══════════════════════════════════════════════════════════════════════════

describe('config.database', () => {
  it('uses defaults when no env vars are set', () => {
    unsetEnvKeys(
      'POSTGRES_HOST',
      'POSTGRES_PORT',
      'POSTGRES_DB',
      'POSTGRES_USER',
      'POSTGRES_PASSWORD',
      'DATABASE_DIR',
      'POSTGREST_BASE_URL'
    );
    const c = loadConfig();

    expect(c.database.host).toBe('localhost');
    expect(c.database.port).toBe(5432);
    expect(c.database.name).toBe('insforge');
    expect(c.database.user).toBe('postgres');
    expect(c.database.password).toBe('postgres');
    expect(c.database.postgrestBaseUrl).toBe('http://localhost:5430');
    expect(typeof c.database.dir).toBe('string');
  });

  it('overrides all database fields', () => {
    process.env.POSTGRES_HOST = 'db.internal';
    process.env.POSTGRES_PORT = '5433';
    process.env.POSTGRES_DB = 'myapp';
    process.env.POSTGRES_USER = 'dbuser';
    process.env.POSTGRES_PASSWORD = 'securepass';
    process.env.POSTGREST_BASE_URL = 'http://postgrest:3000';
    const c = loadConfig();

    expect(c.database.host).toBe('db.internal');
    expect(c.database.port).toBe(5433);
    expect(c.database.name).toBe('myapp');
    expect(c.database.user).toBe('dbuser');
    expect(c.database.password).toBe('securepass');
    expect(c.database.postgrestBaseUrl).toBe('http://postgrest:3000');
  });

  it('parses POSTGRES_PORT as integer', () => {
    process.env.POSTGRES_PORT = '5435';
    expect(loadConfig().database.port).toBe(5435);
    expect(typeof loadConfig().database.port).toBe('number');
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: auth
// ═══════════════════════════════════════════════════════════════════════════

describe('config.auth', () => {
  it('uses defaults when no env vars are set', () => {
    unsetEnvKeys(
      'ROOT_ADMIN_USERNAME',
      'ROOT_ADMIN_PASSWORD',
      'ADMIN_EMAIL',
      'ADMIN_PASSWORD',
      'ACCESS_API_KEY'
    );
    const c = loadConfig();

    expect(c.auth.rootAdminUsername).toBe('');
    expect(c.auth.rootAdminPassword).toBe('');
    expect(c.auth.accessApiKey).toBeUndefined();
  });

  it('overrides root admin credentials', () => {
    process.env.ROOT_ADMIN_USERNAME = 'root-admin';
    process.env.ROOT_ADMIN_PASSWORD = 'ultrasecure!99';
    const c = loadConfig();

    expect(c.auth.rootAdminUsername).toBe('root-admin');
    expect(c.auth.rootAdminPassword).toBe('ultrasecure!99');
  });

  it('keeps ADMIN_EMAIL and ADMIN_PASSWORD as legacy fallbacks', () => {
    unsetEnvKeys('ROOT_ADMIN_USERNAME', 'ROOT_ADMIN_PASSWORD');
    process.env.ADMIN_EMAIL = 'superadmin@company.com';
    process.env.ADMIN_PASSWORD = 'ultrasecure!99';
    const c = loadConfig();

    expect(c.auth.rootAdminUsername).toBe('superadmin@company.com');
    expect(c.auth.rootAdminPassword).toBe('ultrasecure!99');
  });

  it('accessApiKey is set when ACCESS_API_KEY env var is present', () => {
    process.env.ACCESS_API_KEY = 'ik_abc123def456';
    expect(loadConfig().auth.accessApiKey).toBe('ik_abc123def456');
  });

  it('accessApiKey is undefined when ACCESS_API_KEY is not set', () => {
    unsetEnvKeys('ACCESS_API_KEY');
    expect(loadConfig().auth.accessApiKey).toBeUndefined();
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: storage
// ═══════════════════════════════════════════════════════════════════════════

describe('config.storage', () => {
  it('uses defaults when no env vars are set', () => {
    unsetEnvKeys(
      'AWS_S3_BUCKET',
      'APP_KEY',
      'PARENT_APP_KEY',
      'AWS_REGION',
      'STORAGE_DIR',
      'S3_ACCESS_KEY_ID',
      'S3_SECRET_ACCESS_KEY',
      'AWS_ACCESS_KEY_ID',
      'AWS_SECRET_ACCESS_KEY',
      'S3_ENDPOINT_URL',
      'AWS_CONFIG_BUCKET',
      'AWS_CONFIG_REGION'
    );
    const c = loadConfig();

    expect(c.storage.s3Bucket).toBeUndefined();
    expect(c.storage.appKey).toBe('local');
    expect(c.storage.parentAppKey).toBeUndefined();
    expect(c.storage.awsRegion).toBe('us-east-2');
    expect(c.storage.s3AccessKeyId).toBeUndefined();
    expect(c.storage.s3SecretAccessKey).toBeUndefined();
    expect(c.storage.awsAccessKeyId).toBeUndefined();
    expect(c.storage.awsSecretAccessKey).toBeUndefined();
    expect(c.storage.s3EndpointUrl).toBeUndefined();
    expect(c.storage.awsConfigBucket).toBe('insforge-config');
    expect(c.storage.awsConfigRegion).toBe('us-east-2');
    expect(typeof c.storage.storageDir).toBe('string');
  });

  // ── storage.appKey regression ─────────────────────────────────────────────
  it('REGRESSION: storage.appKey defaults to "local" (not "default-app-key")', () => {
    unsetEnvKeys('APP_KEY');
    expect(loadConfig().storage.appKey).toBe('local');
    expect(loadConfig().storage.appKey).not.toBe('default-app-key');
  });

  it('overrides S3 bucket and region', () => {
    process.env.AWS_S3_BUCKET = 'my-production-bucket';
    process.env.AWS_REGION = 'eu-west-1';
    const c = loadConfig();

    expect(c.storage.s3Bucket).toBe('my-production-bucket');
    expect(c.storage.awsRegion).toBe('eu-west-1');
  });

  it('sets s3Bucket to undefined when AWS_S3_BUCKET is not set', () => {
    unsetEnvKeys('AWS_S3_BUCKET');
    expect(loadConfig().storage.s3Bucket).toBeUndefined();
  });

  it('reads S3-specific credentials when set', () => {
    process.env.S3_ACCESS_KEY_ID = 's3-key-id';
    process.env.S3_SECRET_ACCESS_KEY = 's3-secret';
    const c = loadConfig();

    expect(c.storage.s3AccessKeyId).toBe('s3-key-id');
    expect(c.storage.s3SecretAccessKey).toBe('s3-secret');
  });

  it('reads AWS credentials when set', () => {
    process.env.AWS_ACCESS_KEY_ID = 'test-aws-access-key-id';
    process.env.AWS_SECRET_ACCESS_KEY = 'test-aws-secret-access-key';
    const c = loadConfig();

    expect(c.storage.awsAccessKeyId).toBe('test-aws-access-key-id');
    expect(c.storage.awsSecretAccessKey).toBe('test-aws-secret-access-key');
  });

  it('reads S3_ENDPOINT_URL when set', () => {
    process.env.S3_ENDPOINT_URL = 'https://s3.wasabisys.com';
    expect(loadConfig().storage.s3EndpointUrl).toBe('https://s3.wasabisys.com');
  });

  it('S3_ENDPOINT_URL is undefined when not set', () => {
    unsetEnvKeys('S3_ENDPOINT_URL');
    expect(loadConfig().storage.s3EndpointUrl).toBeUndefined();
  });

  it('reads PARENT_APP_KEY and trims whitespace', () => {
    process.env.PARENT_APP_KEY = '  parent-key  ';
    expect(loadConfig().storage.parentAppKey).toBe('parent-key');
  });

  it('PARENT_APP_KEY is undefined when set to only whitespace', () => {
    process.env.PARENT_APP_KEY = '   ';
    expect(loadConfig().storage.parentAppKey).toBeUndefined();
  });

  it('PARENT_APP_KEY is undefined when not set', () => {
    unsetEnvKeys('PARENT_APP_KEY');
    expect(loadConfig().storage.parentAppKey).toBeUndefined();
  });

  it('reads STORAGE_DIR from env', () => {
    process.env.STORAGE_DIR = '/data/insforge-storage';
    expect(loadConfig().storage.storageDir).toBe('/data/insforge-storage');
  });

  it('reads config bucket overrides', () => {
    process.env.AWS_CONFIG_BUCKET = 'my-config-bucket';
    process.env.AWS_CONFIG_REGION = 'ap-southeast-1';
    const c = loadConfig();

    expect(c.storage.awsConfigBucket).toBe('my-config-bucket');
    expect(c.storage.awsConfigRegion).toBe('ap-southeast-1');
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: functions
// ═══════════════════════════════════════════════════════════════════════════

describe('config.functions', () => {
  it('uses default Deno runtime URL', () => {
    unsetEnvKeys('DENO_RUNTIME_URL');
    expect(loadConfig().functions.denoRuntimeUrl).toBe('http://localhost:7133');
  });

  it('overrides Deno runtime URL', () => {
    process.env.DENO_RUNTIME_URL = 'http://deno-runtime:7133';
    expect(loadConfig().functions.denoRuntimeUrl).toBe('http://deno-runtime:7133');
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: deployments
// ═══════════════════════════════════════════════════════════════════════════

describe('config.deployments', () => {
  const ONE_HUNDRED_MIB = 100 * 1024 * 1024;

  it('optional Vercel fields are undefined when not set', () => {
    unsetEnvKeys('VERCEL_TOKEN', 'VERCEL_TEAM_ID', 'VERCEL_PROJECT_ID');
    const c = loadConfig();

    expect(c.deployments.vercelToken).toBeUndefined();
    expect(c.deployments.vercelTeamId).toBeUndefined();
    expect(c.deployments.vercelProjectId).toBeUndefined();
  });

  it('reads Vercel credentials from env', () => {
    process.env.VERCEL_TOKEN = 'vcel_token_abc';
    process.env.VERCEL_TEAM_ID = 'team_xyz';
    process.env.VERCEL_PROJECT_ID = 'prj_123';
    const c = loadConfig();

    expect(c.deployments.vercelToken).toBe('vcel_token_abc');
    expect(c.deployments.vercelTeamId).toBe('team_xyz');
    expect(c.deployments.vercelProjectId).toBe('prj_123');
  });

  it('deployment size limits use 100 MiB defaults', () => {
    unsetEnvKeys('MAX_DEPLOYMENT_FILES', 'MAX_DEPLOYMENT_TOTAL_BYTES', 'MAX_DEPLOYMENT_FILE_BYTES');
    const c = loadConfig();

    expect(c.deployments.maxDeploymentFiles).toBe(5000);
    expect(c.deployments.maxDeploymentTotalBytes).toBe(ONE_HUNDRED_MIB);
    expect(c.deployments.maxDeploymentFileBytes).toBe(ONE_HUNDRED_MIB);
  });

  it('deployment size limits are parsed as integers from env', () => {
    process.env.MAX_DEPLOYMENT_FILES = '1000';
    process.env.MAX_DEPLOYMENT_TOTAL_BYTES = '52428800';
    process.env.MAX_DEPLOYMENT_FILE_BYTES = '10485760';
    const c = loadConfig();

    expect(c.deployments.maxDeploymentFiles).toBe(1000);
    expect(c.deployments.maxDeploymentTotalBytes).toBe(52428800);
    expect(c.deployments.maxDeploymentFileBytes).toBe(10485760);
    expect(typeof c.deployments.maxDeploymentFiles).toBe('number');
    expect(typeof c.deployments.maxDeploymentTotalBytes).toBe('number');
    expect(typeof c.deployments.maxDeploymentFileBytes).toBe('number');
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// Section: ai
// ═══════════════════════════════════════════════════════════════════════════

describe('config.ai', () => {
  it('openrouterApiKey is undefined when not set', () => {
    unsetEnvKeys('OPENROUTER_API_KEY');
    expect(loadConfig().ai.openrouterApiKey).toBeUndefined();
  });

  it('reads OPENROUTER_API_KEY when set', () => {
    process.env.OPENROUTER_API_KEY = 'sk-or-test-key-12345';
    expect(loadConfig().ai.openrouterApiKey).toBe('sk-or-test-key-12345');
  });
});

// ═══════════════════════════════════════════════════════════════════════════
// loadConfig() structural integrity
// ═══════════════════════════════════════════════════════════════════════════

describe('loadConfig() structural integrity', () => {
  it('returns a complete object with all 11 top-level sections', () => {
    const c = loadConfig();

    expect(c).toHaveProperty('app');
    expect(c).toHaveProperty('cloud');
    expect(c).toHaveProperty('denoSubhosting');
    expect(c).toHaveProperty('fly');
    expect(c).toHaveProperty('server');
    expect(c).toHaveProperty('database');
    expect(c).toHaveProperty('auth');
    expect(c).toHaveProperty('storage');
    expect(c).toHaveProperty('functions');
    expect(c).toHaveProperty('deployments');
    expect(c).toHaveProperty('ai');
  });

  it('returns a new object each time (not a cached singleton)', () => {
    process.env.PORT = '8001';
    const c1 = loadConfig();
    process.env.PORT = '8002';
    const c2 = loadConfig();

    expect(c1.app.port).toBe(8001);
    expect(c2.app.port).toBe(8002);
    expect(c1).not.toBe(c2);
  });

  it('all numeric fields are actual numbers (not strings)', () => {
    const c = loadConfig();

    expect(typeof c.app.port).toBe('number');
    expect(typeof c.database.port).toBe('number');
    expect(typeof c.server.maxFilesPerField).toBe('number');
    expect(typeof c.deployments.maxDeploymentFiles).toBe('number');
    expect(typeof c.deployments.maxDeploymentTotalBytes).toBe('number');
    expect(typeof c.deployments.maxDeploymentFileBytes).toBe('number');
  });

  it('no numeric field is NaN', () => {
    const c = loadConfig();

    expect(c.app.port).not.toBeNaN();
    expect(c.database.port).not.toBeNaN();
    expect(c.server.maxFilesPerField).not.toBeNaN();
    expect(c.deployments.maxDeploymentFiles).not.toBeNaN();
    expect(c.deployments.maxDeploymentTotalBytes).not.toBeNaN();
    expect(c.deployments.maxDeploymentFileBytes).not.toBeNaN();
  });
});
