// Import necessary types
import { EnvLoader } from './loaders/env.loader';
import { FileLoader } from './loaders/file.loader';
import { ConfigManager } from './config-manager';
import type { AppConfig } from './schemas';
import { appConfigSchema } from './schemas';
import { z } from 'zod';

// Legacy singleton instance for backward compatibility
let configInstance: ConfigManager<AppConfig> | null = null;

// Synchronously load critical env vars for early initialization
function loadCriticalEnvVarsSync(): void {
  // Load .env file synchronously if it exists
  try {
    const fs = require('fs');
    const path = require('path');
    const envPath = path.resolve(process.cwd(), '.env');
    if (fs.existsSync(envPath)) {
      const envContent = fs.readFileSync(envPath, 'utf-8');
      const lines = envContent.split('\n');

      for (const line of lines) {
        const trimmed = line.trim();
        if (!trimmed || trimmed.startsWith('#')) {
          continue;
        }

        const equalIndex = trimmed.indexOf('=');
        if (equalIndex === -1) {
          continue;
        }

        const key = trimmed.substring(0, equalIndex).trim();
        let value = trimmed.substring(equalIndex + 1).trim();

        // Remove surrounding quotes
        if (
          (value.startsWith('"') && value.endsWith('"')) ||
          (value.startsWith("'") && value.endsWith("'"))
        ) {
          value = value.slice(1, -1);
        }

        // Only set if not already set
        if (!(key in process.env)) {
          process.env[key] = value;
        }
      }
    }
  } catch {
    // Ignore errors - env file is optional
  }
}

// Load critical env vars immediately
loadCriticalEnvVarsSync();

/**
 * Initialize the global configuration synchronously.
 * @deprecated Use initializeAppConfig with your own schema instead
 *
 * This loads configuration from all sources in the correct hierarchy:
 * 1. Schema defaults (lowest priority)
 * 2. default.json
 * 3. [environment].json (e.g., development.json)
 * 4. .env file values
 * 5. process.env values (highest priority)
 */
export function initializeConfig(configPath?: string): AppConfig {
  if (!configInstance) {
    configInstance = new ConfigManager<AppConfig>({
      configPath,
    });
  }
  return configInstance.initialize(appConfigSchema);
}

/**
 * Initialize configuration for a service in a monorepo.
 * Automatically loads configs from:
 * 1. Root config directory (../../config)
 * 2. Service-specific config directory (./config)
 * 3. Environment variables
 */
export function initializeServiceConfig(): AppConfig {
  if (!configInstance) {
    const environment = process.env.NODE_ENV || 'development';
    configInstance = new ConfigManager<AppConfig>({
      loaders: [
        new FileLoader('../../config', environment), // Root config
        new FileLoader('./config', environment), // Service config
        new EnvLoader(''), // Environment variables
      ],
    });
  }
  return configInstance.initialize(appConfigSchema);
}

/**
 * Get the current configuration
 */
export function getConfig(): AppConfig {
  if (!configInstance) {
    throw new Error('Configuration not initialized. Call initializeConfig() first.');
  }
  return configInstance.get();
}

/**
 * Get configuration manager instance
 */
export function getConfigManager(): ConfigManager<AppConfig> {
  if (!configInstance) {
    throw new Error('Configuration not initialized. Call initializeConfig() first.');
  }
  return configInstance;
}

/**
 * Reset configuration (useful for testing)
 */
export function resetConfig(): void {
  if (configInstance) {
    configInstance.reset();
    configInstance = null;
  }
}

// Export convenience functions for common configs
export function getDatabaseConfig() {
  return getConfig().database;
}

export function getServiceConfig() {
  return getConfig().service;
}

export function getLogConfig() {
  return getConfig().log;
}

// Deprecated alias for backward compatibility
export function getLoggingConfig() {
  return getConfig().log;
}

// Deprecated - provider configs should be app-specific
// @deprecated Move provider configs to your app-specific config
export function getProviderConfig(_provider: string) {
  const config = getConfig() as any;
  const providers = config.providers;
  if (!providers || !(_provider in providers)) {
    throw new Error(`Provider configuration not found: ${_provider}`);
  }
  return (providers as Record<string, unknown>)[_provider];
}

export function getQueueConfig() {
  return getConfig().queue;
}

// Export environment helpers
export function isDevelopment(): boolean {
  return getConfig().environment === 'development';
}

export function isProduction(): boolean {
  return getConfig().environment === 'production';
}

export function isTest(): boolean {
  return getConfig().environment === 'test';
}

/**
 * Generic config builder for creating app-specific configurations
 * @param schema - Zod schema for your app config
 * @param options - Config manager options
 * @returns Initialized config manager instance
 */
export function createAppConfig<T extends z.ZodSchema>(
  schema: T,
  options?: {
    configPath?: string;
    environment?: 'development' | 'test' | 'production';
    loaders?: any[];
  }
): ConfigManager<z.infer<T>> {
  const manager = new ConfigManager<z.infer<T>>(options);
  return manager;
}

/**
 * Create and initialize app config in one step
 */
export function initializeAppConfig<T extends z.ZodSchema>(
  schema: T,
  options?: {
    configPath?: string;
    environment?: 'development' | 'test' | 'production';
    loaders?: any[];
  }
): z.infer<T> {
  const manager = createAppConfig(schema, options);
  return manager.initialize(schema);
}

// Export all schemas
export * from './schemas';

// Export types
export * from './types';

// Export errors
export * from './errors';

// Export loaders
export { EnvLoader } from './loaders/env.loader';
export { FileLoader } from './loaders/file.loader';

// Export ConfigManager
export { ConfigManager } from './config-manager';

// Export utilities
export * from './utils/secrets';
export * from './utils/validation';
