import { normalizeProviderConfig } from '@robota-sdk/agent-executor';

import { NodeFileSystem } from '../../adapters/node-file-system.js';
import { SettingsParseError } from '../../config/settings-parse-error.js';

import type { IProviderProfileSettings, TProviderSettingsDocument } from './provider-settings.js';
import type { IFileSystem } from '@robota-sdk/agent-core';
import type { IProviderConfig, IProviderDefinition } from '@robota-sdk/agent-core';

export function readMergedProviderSettingsFromPaths(
  paths: readonly string[],
  fs: IFileSystem = new NodeFileSystem(),
): TProviderSettingsDocument {
  return paths.reduce<TProviderSettingsDocument>((settings, filePath) => {
    const parsed = readSettingsFile(filePath, fs);
    if (parsed === undefined) {
      return settings;
    }
    return mergeSettings(settings, parsed);
  }, {});
}

/**
 * CLI-069: a missing file is a non-error (undefined); an EXISTING file that
 * fails to parse throws SettingsParseError — corrupt is never treated as missing.
 */
function readSettingsFile(
  filePath: string,
  fs: IFileSystem,
): TProviderSettingsDocument | undefined {
  if (!fs.existsSync(filePath)) {
    return undefined;
  }
  const raw = fs.readFileSync(filePath, 'utf8');
  try {
    return JSON.parse(raw) as TProviderSettingsDocument;
  } catch (error) {
    // allow-fallback: rethrown as typed SettingsParseError — fail-fast, not a fallback
    throw new SettingsParseError(filePath, error instanceof Error ? error.message : String(error));
  }
}

export function mergeSettings(
  base: TProviderSettingsDocument,
  override: TProviderSettingsDocument,
): TProviderSettingsDocument {
  return {
    ...base,
    ...override,
    provider:
      base.provider !== undefined || override.provider !== undefined
        ? { ...base.provider, ...override.provider }
        : undefined,
    providers:
      base.providers !== undefined || override.providers !== undefined
        ? mergeProviders(base.providers, override.providers)
        : undefined,
  };
}

export function mergeProviders(
  base: TProviderSettingsDocument['providers'],
  override: TProviderSettingsDocument['providers'],
): TProviderSettingsDocument['providers'] {
  const result: Record<string, IProviderProfileSettings> = { ...(base ?? {}) };
  for (const [name, profile] of Object.entries(override ?? {})) {
    result[name] = { ...result[name], ...profile };
  }
  return result;
}

export function resolveActiveProvider(
  settings: TProviderSettingsDocument,
  providerOverride: string | undefined,
  providerDefinitions: readonly IProviderDefinition[],
): IProviderConfig | undefined {
  const activeProvider = providerOverride ?? settings.currentProvider;
  if (activeProvider !== undefined) {
    const profile = settings.providers?.[activeProvider];
    if (profile === undefined) {
      throw new Error(`Provider profile "${activeProvider}" was not found in providers`);
    }
    if (!profile.type) {
      throw new Error(`Provider profile "${activeProvider}" is missing type`);
    }
    return normalizeProviderConfig(
      {
        name: profile.type,
        model: profile.model,
        apiKey: profile.apiKey,
        baseURL: profile.baseURL,
        timeout: profile.timeout,
        options: profile.options,
      },
      providerDefinitions,
    );
  }

  const provider = settings.provider;
  if (provider?.name) {
    return normalizeProviderConfig(
      {
        name: provider.name,
        model: provider.model,
        apiKey: provider.apiKey,
        baseURL: provider.baseURL,
        timeout: provider.timeout,
        options: provider.options,
      },
      providerDefinitions,
    );
  }

  return undefined;
}
