import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import { ConfigLoaderError } from '../errors';
import type { ConfigLoader } from '../types';

export class FileLoader implements ConfigLoader {
  readonly priority = 50; // Medium priority

  constructor(
    private configPath: string,
    private environment: string
  ) {}

  load(): Record<string, unknown> {
    try {
      const configs: Record<string, unknown>[] = [];

      // Load default config
      const defaultConfig = this.loadFile('default.json');
      if (defaultConfig) {
        configs.push(defaultConfig);
      }

      // Load environment-specific config
      const envConfig = this.loadFile(`${this.environment}.json`);
      if (envConfig) {
        configs.push(envConfig);
      }

      // Merge configs (later configs override earlier ones)
      return this.deepMerge(...configs);
    } catch (error) {
      throw new ConfigLoaderError(`Failed to load configuration files: ${error}`, 'FileLoader');
    }
  }

  private loadFile(filename: string): Record<string, unknown> | null {
    const filepath = join(this.configPath, filename);

    if (!existsSync(filepath)) {
      return null;
    }

    const content = readFileSync(filepath, 'utf-8');
    return JSON.parse(content);
  }

  private deepMerge(...objects: Record<string, unknown>[]): Record<string, unknown> {
    const result: Record<string, unknown> = {};

    for (const obj of objects) {
      for (const [key, value] of Object.entries(obj)) {
        if (value === null || value === undefined) {
          result[key] = value;
        } else if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
          result[key] = this.deepMerge(
            (result[key] as Record<string, unknown>) || {},
            value as Record<string, unknown>
          );
        } else {
          result[key] = value;
        }
      }
    }

    return result;
  }
}
