export type ContractDisposition = 'supported' | 'deferred' | 'retired';

export interface V3ContractCatalogEntry {
  name: string;
  module: string;
  disposition: ContractDisposition;
  deployment: 'unconfigured' | 'not-in-pilot' | 'prohibited';
  address: null;
  sourceAvailable: boolean;
  executableEvidenceAvailable: false;
  reason: string;
}

const supported = [
  ['MultisigGovernanceV3', 'governance'],
  ['BasePilotAccessControllerV3', 'pilot-control'],
  ['ThresholdConsensusV3', 'consensus'],
  ['DisputeRegistryV3', 'disputes'],
  ['SafeBondFactoryV3', 'bonds'],
  ['PartnershipBondFactoryV3', 'bonds'],
  ['AccountabilityBondFactoryV3', 'bonds'],
  ['PartnershipBondV3Safe', 'bonds'],
  ['AccountabilityBondV3Safe', 'bonds'],
] as const;

const deferred = [
  ['RewardProgramV3', 'rewards'],
  ['TaskEscrowV3', 'tasks'],
  ['MutualAidPoolV3', 'mutual-aid'],
  ['VaultfireBIPVaultV3', 'vault'],
  ['ERC8004ValidationRegistryV3Safe', 'validation'],
  ['StreetCredV3', 'reputation'],
  ['LegacyKYAAdapterV3', 'identity'],
  ['ERC8004IdentityAdapterV3', 'identity'],
  ['EvidenceRegistryV3', 'evidence'],
  ['MandateRegistryV3', 'mandates'],
  ['MandateExecutionAdapterV3', 'mandates'],
] as const;

export const V3_CONTRACT_CATALOG: readonly V3ContractCatalogEntry[] = Object.freeze([
  ...supported.map(([name, module]) => Object.freeze({
    name, module, disposition: 'supported' as const, deployment: 'unconfigured' as const,
    address: null, sourceAvailable: true, executableEvidenceAvailable: false as const,
    reason: 'Enabled by the bonds-only pilot scope, but no verified deployment address or executable evidence is configured.',
  })),
  ...deferred.map(([name, module]) => Object.freeze({
    name, module, disposition: 'deferred' as const, deployment: 'not-in-pilot' as const,
    address: null, sourceAvailable: true, executableEvidenceAvailable: false as const,
    reason: 'Explicitly disabled by the current bonds-only pilot manifest.',
  })),
  Object.freeze({
    name: 'FlourishingMetricsOracleV3', module: 'flourishing', disposition: 'retired' as const,
    deployment: 'prohibited' as const, address: null, sourceAvailable: true,
    executableEvidenceAvailable: false as const,
    reason: 'Subjective flourishing metrics are excluded from V3 routing and protected decisions.',
  }),
  Object.freeze({
    name: 'BeliefAttestationVerifierV3', module: 'belief', disposition: 'retired' as const,
    deployment: 'prohibited' as const, address: null, sourceAvailable: true,
    executableEvidenceAvailable: false as const,
    reason: 'Belief-derived inputs are excluded from V3 custody, access, eligibility, pricing, settlement, slashing, disputes, and routing.',
  }),
]);

const byName = new Map(V3_CONTRACT_CATALOG.map((entry) => [entry.name.toLowerCase(), entry]));

export function getV3Contract(name: string): V3ContractCatalogEntry | null {
  return byName.get(name.toLowerCase()) ?? null;
}

export function assertV3ContractCatalog(value: unknown): asserts value is readonly V3ContractCatalogEntry[] {
  if (!Array.isArray(value) || value.length !== V3_CONTRACT_CATALOG.length) throw new Error('invalid V3 contract catalog');
  const names = new Set<string>();
  for (const candidate of value) {
    const entry = candidate as V3ContractCatalogEntry;
    if (
      !entry?.name || names.has(entry.name) || !entry.module ||
      !['supported', 'deferred', 'retired'].includes(entry.disposition) ||
      entry.address !== null || entry.executableEvidenceAvailable !== false ||
      typeof entry.sourceAvailable !== 'boolean' || !entry.reason
    ) throw new Error(`invalid V3 contract catalog entry: ${entry?.name}`);
    names.add(entry.name);
  }
}

assertV3ContractCatalog(V3_CONTRACT_CATALOG);
