/**
 * K8s-aligned Configuration Loader
 * Loads configuration from YAML files and secrets from mounted files
 * Replaces environment variable based configuration for production k8s compatibility
 */
import * as yaml from 'js-yaml';
import * as fs from 'fs';
import * as path from 'path';
import { z } from 'zod';
import { logger } from '../logging/logger';

// Configuration schema definition
const configSchema = z.object({
  // Server configuration
  server: z.object({
    name: z.string(),
    port: z.number(),
    environment: z.string(),
    node_env: z.string(),
  }),

  // Database configuration
  database: z.object({
    host: z.string(),
    port: z.number(),
    name: z.string(),
    user: z.string(),
    pool_size: z.number().optional().default(20),
  }),

  // Redis configuration
  redis: z.object({
    host: z.string(),
    port: z.number(),
    db: z.number().optional().default(0),
  }),

  // Auth0 configuration
  auth0: z.object({
    domain: z.string(),
    audience: z.string(),
  }),

  // External APIs configuration (optional)
  external: z.object({
    vpic: z.object({
      url: z.string(),
      timeout: z.string(),
    }).optional(),
  }).optional(),

  // Service configuration
  service: z.object({
    name: z.string(),
  }),

  // CORS configuration
  cors: z.object({
    origins: z.array(z.string()),
    allow_credentials: z.boolean(),
    max_age: z.number(),
  }),

  // Frontend configuration
  frontend: z.object({
    api_base_url: z.string(),
    auth0: z.object({
      domain: z.string(),
      audience: z.string(),
    }),
  }),

  // Health check configuration
  health: z.object({
    endpoints: z.object({
      basic: z.string(),
      ready: z.string(),
      live: z.string(),
      startup: z.string(),
    }),
    probes: z.object({
      startup: z.object({
        initial_delay: z.string(),
        period: z.string(),
        timeout: z.string(),
        failure_threshold: z.number(),
      }),
      readiness: z.object({
        period: z.string(),
        timeout: z.string(),
        failure_threshold: z.number(),
      }),
      liveness: z.object({
        period: z.string(),
        timeout: z.string(),
        failure_threshold: z.number(),
      }),
    }),
  }),

  // Logging configuration
  logging: z.object({
    level: z.string(),
    format: z.string(),
    destinations: z.array(z.string()),
  }),

  // Performance configuration
  performance: z.object({
    request_timeout: z.string(),
    max_request_size: z.string(),
    compression_enabled: z.boolean(),
    circuit_breaker: z.object({
      enabled: z.boolean(),
      failure_threshold: z.number(),
      timeout: z.string(),
    }),
  }),
});

// Secrets schema definition
const secretsSchema = z.object({
  postgres_password: z.string(),
  auth0_client_secret: z.string(),
  auth0_management_client_id: z.string(),
  auth0_management_client_secret: z.string(),
  google_maps_api_key: z.string(),
  resend_api_key: z.string(),
  // Stripe secrets (API keys only - price IDs are config, not secrets)
  stripe_secret_key: z.string(),
  stripe_webhook_secret: z.string(),
});

type Config = z.infer<typeof configSchema>;
type Secrets = z.infer<typeof secretsSchema>;

export interface AppConfiguration {
  config: Config;
  secrets: Secrets;

  // Convenience accessors for common patterns
  getDatabaseUrl(): string;
  getRedisUrl(): string;
  getAuth0Config(): { domain: string; audience: string; clientSecret: string };
  getAuth0ManagementConfig(): { domain: string; clientId: string; clientSecret: string };
  getStripeConfig(): {
    secretKey: string;
    webhookSecret: string;
  };
}

class ConfigurationLoader {
  private configPath: string;
  private secretsDir: string;
  private cachedConfig: AppConfiguration | null = null;

  constructor() {
    this.configPath = process.env['CONFIG_PATH'] || '/app/config/production.yml';
    this.secretsDir = process.env['SECRETS_DIR'] || '/run/secrets';
  }

  private loadYamlConfig(): Config {
    if (!fs.existsSync(this.configPath)) {
      throw new Error(`Configuration file not found at ${this.configPath}`);
    }

    try {
      const fileContents = fs.readFileSync(this.configPath, 'utf8');
      const yamlData = yaml.load(fileContents) as any;

      return configSchema.parse(yamlData);
    } catch (error) {
      logger.error(`Failed to load configuration from ${this.configPath}`, { error });
      throw new Error(`Configuration loading failed: ${error}`);
    }
  }

  private loadSecrets(): Secrets {
    const secrets: Partial<Secrets> = {};

    const secretFiles = [
      'postgres-password',
      'auth0-client-secret',
      'auth0-management-client-id',
      'auth0-management-client-secret',
      'google-maps-api-key',
      'resend-api-key',
      'stripe-secret-key',
      'stripe-webhook-secret',
    ];

    for (const secretFile of secretFiles) {
      const secretPath = path.join(this.secretsDir, secretFile);
      const secretKey = secretFile.replace(/-/g, '_') as keyof Secrets;

      if (fs.existsSync(secretPath)) {
        try {
          const secretValue = fs.readFileSync(secretPath, 'utf8').trim();
          (secrets as any)[secretKey] = secretValue;
        } catch (error) {
          logger.error(`Failed to read secret file ${secretPath}`, { error });
        }
      } else {
        logger.error(`Secret file not found: ${secretPath}`);
      }
    }

    try {
      return secretsSchema.parse(secrets);
    } catch (error) {
      logger.error('Secrets validation failed', { error });
      throw new Error(`Secrets loading failed: ${error}`);
    }
  }


  public load(): AppConfiguration {
    if (this.cachedConfig) {
      return this.cachedConfig;
    }

    const config = this.loadYamlConfig();
    const secrets = this.loadSecrets();

    this.cachedConfig = {
      config,
      secrets,

      getDatabaseUrl(): string {
        return `postgresql://${config.database.user}:${secrets.postgres_password}@${config.database.host}:${config.database.port}/${config.database.name}`;
      },

      getRedisUrl(): string {
        return `redis://${config.redis.host}:${config.redis.port}/${config.redis.db}`;
      },

      getAuth0Config() {
        return {
          domain: config.auth0.domain,
          audience: config.auth0.audience,
          clientSecret: secrets.auth0_client_secret,
        };
      },

      getAuth0ManagementConfig() {
        return {
          domain: config.auth0.domain,
          clientId: secrets.auth0_management_client_id,
          clientSecret: secrets.auth0_management_client_secret,
        };
      },

      getStripeConfig() {
        return {
          secretKey: secrets.stripe_secret_key,
          webhookSecret: secrets.stripe_webhook_secret,
        };
      },
    };

    // Set RESEND_API_KEY in environment for EmailService
    process.env['RESEND_API_KEY'] = secrets.resend_api_key;

    logger.info('Configuration loaded successfully', {
      configSource: 'yaml',
      secretsSource: 'files',
    });

    return this.cachedConfig;
  }
}

// Export singleton instance
const configLoader = new ConfigurationLoader();
export const appConfig = configLoader.load();

// Export types for use in other modules
export type { Config, Secrets };