import type {
  ConfigurationDefinition,
  ConfigurationOverride,
  ConfigurationScope,
  EffectiveConfiguration,
} from "@awp/contracts";

const scopeOrder: readonly ConfigurationScope[] = ["system", "project", "plan", "task", "run"];

export class ConfigurationRegistry {
  readonly #definitions = new Map<string, ConfigurationDefinition<unknown>>();
  register<T>(definition: ConfigurationDefinition<T>): void {
    if (this.#definitions.has(definition.key))
      throw new Error(`Configuration already registered: ${definition.key}`);
    this.#definitions.set(definition.key, definition as ConfigurationDefinition<unknown>);
  }
  get(key: string): ConfigurationDefinition<unknown> | undefined {
    return this.#definitions.get(key);
  }
}

export function resolveConfiguration<T>(
  definition: ConfigurationDefinition<T>,
  overrides: readonly ConfigurationOverride<T>[],
): EffectiveConfiguration<T> {
  const legal = overrides.filter((item) => definition.allowedScopes.includes(item.scopeType));
  legal.sort((a, b) => scopeOrder.indexOf(a.scopeType) - scopeOrder.indexOf(b.scopeType));
  const provenanceChain = legal.map(({ scopeType, scopeId }) => ({ scopeType, scopeId }));
  const selected = definition.overrideStrategy === "deny-lower-override" ? legal[0] : legal.at(-1);
  if (selected)
    return {
      value: selected.value,
      sourceScope: selected.scopeType,
      sourceId: selected.scopeId,
      provenanceChain,
    };
  if (definition.defaultValue === undefined)
    throw new Error(`No value configured for ${definition.key}`);
  return {
    value: definition.defaultValue,
    sourceScope: "system",
    sourceId: "default",
    provenanceChain: [],
  };
}
