// backend/src/config/configuration.ts

/** Matches values accepted by jsonwebtoken `expiresIn` (via ms), e.g. 7d, 15m, or plain seconds. */
const JWT_TIMESPAN_PATTERN =
  /^\d+(\.\d+)?(ms|s|m|h|d|w|y)?$/i;

function assertJwtSecret(value: string, envKey: string): string {
  const trimmed = value.trim();
  if (!trimmed) {
    throw new Error(`❌ Environment variable ${envKey} is required but not set`);
  }
  if (trimmed.length < 16) {
    throw new Error(`❌ ${envKey} must be at least 16 characters`);
  }
  if (/CHANGE_ME/i.test(trimmed)) {
    throw new Error(`❌ ${envKey} must be changed from the placeholder value`);
  }
  return trimmed;
}

function assertJwtTimespan(value: string, envKey: string): string {
  const trimmed = value.trim();
  if (!trimmed) {
    throw new Error(`❌ Environment variable ${envKey} is required but not set`);
  }
  if (!/^\d+$/.test(trimmed) && !JWT_TIMESPAN_PATTERN.test(trimmed)) {
    throw new Error(
      `❌ ${envKey}="${value}" is invalid. Use a duration like 7d, 15m, 30d, or a number of seconds.`,
    );
  }
  return trimmed;
}

function parseEnvBoolean(value: string | undefined, defaultValue: boolean): boolean {
  if (value === undefined || value.trim() === '') {
    return defaultValue;
  }
  const normalized = value.trim().toLowerCase();
  if (['1', 'true', 'yes', 'on'].includes(normalized)) {
    return true;
  }
  if (['0', 'false', 'no', 'off'].includes(normalized)) {
    return false;
  }
  return defaultValue;
}

export interface Config {
  port: number;
  database: {
    url: string;
  };
  jwt: {
    secret: string;
    expiresIn: string;
    refreshSecret: string;
    refreshExpiresIn: string;
  };
  cookie: {
    secure: boolean;
  };
  throttle: {
    ttl: number;
    limit: number;
  };
  sms: {
    apiKey: string | null;
    templateId: number;
  };
}

export default (): Config => {
  // Helper function to get required env var with type safety
  const getEnvVar = (key: string): string => {
    const value = process.env[key];
    if (!value) {
      throw new Error(`❌ Environment variable ${key} is required but not set`);
    }
    return value;
  };

  // Helper for optional env vars with defaults (whitespace-only counts as unset)
  const getEnvVarWithDefault = (key: string, defaultValue: string): string => {
    const value = process.env[key]?.trim();
    return value ? value : defaultValue;
  };

  const getEnvVarAsNumber = (key: string, defaultValue: number): number => {
    const value = process.env[key];
    if (!value) return defaultValue;
    const parsed = parseInt(value, 10);
    return isNaN(parsed) ? defaultValue : parsed;
  };

  const jwtSecret = assertJwtSecret(getEnvVar('JWT_SECRET'), 'JWT_SECRET');
  const jwtExpiresIn = assertJwtTimespan(
    getEnvVarWithDefault('JWT_EXPIRES_IN', '7d'),
    'JWT_EXPIRES_IN',
  );
  const jwtRefreshSecret = assertJwtSecret(
    getEnvVarWithDefault('JWT_REFRESH_SECRET', jwtSecret),
    'JWT_REFRESH_SECRET',
  );
  const jwtRefreshExpiresIn = assertJwtTimespan(
    getEnvVarWithDefault('JWT_REFRESH_EXPIRES_IN', '30d'),
    'JWT_REFRESH_EXPIRES_IN',
  );
  const cookieSecure = parseEnvBoolean(process.env.COOKIE_SECURE, false);

  return {
    port: getEnvVarAsNumber('PORT', 3000),
    database: {
      url: getEnvVar('DATABASE_URL'),
    },
    jwt: {
      secret: jwtSecret,
      expiresIn: jwtExpiresIn,
      refreshSecret: jwtRefreshSecret,
      refreshExpiresIn: jwtRefreshExpiresIn,
    },
    cookie: {
      secure: cookieSecure,
    },
    throttle: {
      ttl: getEnvVarAsNumber('THROTTLE_TTL', 60),
      limit: getEnvVarAsNumber('THROTTLE_LIMIT', 100),
    },
    sms: {
      apiKey: process.env.SMS_IR_API_KEY?.trim() || null,
      templateId: getEnvVarAsNumber('SMS_IR_TEMPLATE_ID', 123456),
    },
  };
};