/**
 * v2.3 provider config file (`/data/coder-providers.json`) — schema + loader.
 *
 * Layers config-backed overrides/custom-ACP entries over the hardcoded built-ins
 * (see provider-config-registry.ts). Loading NEVER throws at startup (design.md
 * §2.1): a missing file, invalid JSON, or schema mismatch all fall back to
 * `{ providers: {} }` (built-ins only, all enabled).
 *
 * Schemas are defined once in @boocode/contracts/provider-config and re-exported
 * here so existing importers (routes, tests, registry) don't need path changes.
 */
import { readFileSync, writeFileSync } from 'node:fs';
import {
  ProviderOverrideSchema,
  CoderProvidersFileSchema,
  ProviderConfigPatchSchema,
  type ProviderOverride,
  type CoderProvidersFile,
  type ProviderConfigPatch,
} from '@boocode/contracts/provider-config';

export {
  ProviderOverrideSchema,
  CoderProvidersFileSchema,
  ProviderConfigPatchSchema,
  type ProviderOverride,
  type CoderProvidersFile,
  type ProviderConfigPatch,
};

/**
 * Shallow per-id merge (design.md §6.2 / Paseo `patchConfig`). Each key in
 * `patch.providers` REPLACES that id's override object wholesale (NOT a deep
 * field merge); a `null` value DELETES the override. Returns a new object —
 * never mutates `current`. The result is a plain CoderProvidersFile (no nulls),
 * which the route re-validates against CoderProvidersFileSchema before save.
 */
export function mergeProviderConfigPatch(
  current: CoderProvidersFile,
  patch: ProviderConfigPatch,
): CoderProvidersFile {
  const providers: Record<string, ProviderOverride> = { ...current.providers };
  for (const [id, override] of Object.entries(patch.providers)) {
    if (override === null) {
      delete providers[id];
    } else {
      providers[id] = override;
    }
  }
  return { providers };
}

/** Read + parse + validate. Falls back to built-ins-only on any failure; never throws. */
export function load(path: string): CoderProvidersFile {
  let raw: string;
  try {
    raw = readFileSync(path, 'utf8');
  } catch {
    // Missing file → built-ins only. Expected, not an error.
    return { providers: {} };
  }

  let json: unknown;
  try {
    json = JSON.parse(raw);
  } catch (err) {
    console.error(`provider-config: invalid JSON in ${path} — using built-ins only`, err);
    return { providers: {} };
  }

  const parsed = CoderProvidersFileSchema.safeParse(json);
  if (!parsed.success) {
    console.error(
      `provider-config: schema validation failed for ${path} — using built-ins only`,
      parsed.error.flatten(),
    );
    return { providers: {} };
  }

  return parsed.data;
}

export function save(path: string, config: CoderProvidersFile): void {
  writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
}
