import type { V3ReadDisposition } from './http';

export interface V3ApiRoute {
  id: string;
  method: 'GET' | 'POST';
  path: string;
  canonicalSdkRoute: string | null;
  disposition: V3ReadDisposition;
  readOnly: true;
  deploymentRequired: boolean;
  responseSchema: string;
  responseStatuses: readonly number[];
  description: string;
}

const SCHEMA_ROOT = 'https://theloopbreaker.com/schemas/v3-x402/';
export const V3_API_ROUTES: readonly V3ApiRoute[] = Object.freeze([
  { id: 'contracts', method: 'GET', path: '/api/v3/contracts', canonicalSdkRoute: null, disposition: 'supported', readOnly: true, deploymentRequired: false, responseSchema: `${SCHEMA_ROOT}contract-catalog.v1.schema.json`, responseStatuses: [200, 503], description: 'Static V3 contract catalog and deployment dispositions.' },
  { id: 'contract', method: 'GET', path: '/api/v3/contracts/:name', canonicalSdkRoute: null, disposition: 'supported', readOnly: true, deploymentRequired: false, responseSchema: `${SCHEMA_ROOT}contract-result.v1.schema.json`, responseStatuses: [200, 400, 404, 503], description: 'Static V3 contract metadata by canonical name.' },
  { id: 'bond-party', method: 'GET', path: '/api/v3/bonds', canonicalSdkRoute: 'bonds', disposition: 'supported', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'Bond query by required party query parameter; fail-closed while deployment/read adapter is absent.' },
  { id: 'bond', method: 'GET', path: '/api/v3/bonds/:bondId', canonicalSdkRoute: 'bonds', disposition: 'supported', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'Bond read model by numeric ID.' },
  { id: 'dispute', method: 'GET', path: '/api/v3/disputes/:disputeId', canonicalSdkRoute: null, disposition: 'supported', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'Objective dispute record by numeric ID.' },
  { id: 'evidence', method: 'GET', path: '/api/v3/evidence/:evidenceHash', canonicalSdkRoute: null, disposition: 'degraded', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'Evidence record; module is deferred by the pilot manifest.' },
  { id: 'task', method: 'GET', path: '/api/v3/tasks/:taskId', canonicalSdkRoute: 'taskEscrow', disposition: 'degraded', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'Task escrow read model; module is deferred by the pilot manifest.' },
  { id: 'mandate', method: 'GET', path: '/api/v3/mandates/:mandateHash', canonicalSdkRoute: 'mandates', disposition: 'degraded', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'Canonical plural mandate lookup.' },
  { id: 'mandate-compat', method: 'GET', path: '/api/v3/mandate/:mandateHash', canonicalSdkRoute: 'mandates', disposition: 'degraded', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'Singular V3-only compatibility wrapper; never falls back to V2.' },
  { id: 'governance-proposal', method: 'GET', path: '/api/v3/governance/proposals/:proposalId', canonicalSdkRoute: 'governance', disposition: 'supported', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'Governance proposal status by numeric ID.' },
  { id: 'pull-credit', method: 'GET', path: '/api/v3/pull-credits', canonicalSdkRoute: 'pullCredits', disposition: 'supported', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'Pull-payment credit balance query with required contract, asset, and holder parameters.' },
  { id: 'migration', method: 'GET', path: '/api/v3/migration/dispositions', canonicalSdkRoute: null, disposition: 'supported', readOnly: true, deploymentRequired: false, responseSchema: `${SCHEMA_ROOT}migration-dispositions.v1.schema.json`, responseStatuses: [200, 503], description: 'Supported, deferred, unavailable, and retired migration dispositions.' },
  { id: 'status', method: 'GET', path: '/api/v3/protocol/status', canonicalSdkRoute: null, disposition: 'supported', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}status.v1.schema.json`, responseStatuses: [503], description: 'Protocol deployment/read-adapter readiness.' },
  { id: 'solvency', method: 'GET', path: '/api/v3/protocol/solvency', canonicalSdkRoute: 'solvency', disposition: 'supported', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}solvency.v1.schema.json`, responseStatuses: [503], description: 'Protocol solvency read model.' },
  { id: 'x402-discovery', method: 'GET', path: '/api/v3/x402/discovery', canonicalSdkRoute: 'x402.discovery', disposition: 'unavailable', readOnly: true, deploymentRequired: false, responseSchema: `${SCHEMA_ROOT}discovery.v1.schema.json`, responseStatuses: [200, 503], description: 'Static fail-closed x402 discovery document.' },
  { id: 'x402-challenge-status', method: 'GET', path: '/api/v3/x402/challenge-status', canonicalSdkRoute: 'x402.challenge', disposition: 'unavailable', readOnly: true, deploymentRequired: false, responseSchema: `${SCHEMA_ROOT}challenge-status.v1.schema.json`, responseStatuses: [200, 503], description: 'Static x402 challenge capability status.' },
  { id: 'x402-challenge', method: 'GET', path: '/api/v3/x402/challenges/:challengeId', canonicalSdkRoute: 'x402.challenge', disposition: 'unavailable', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}read-result.v1.schema.json`, responseStatuses: [400, 503], description: 'x402 challenge read model by bytes32 ID.' },
  { id: 'x402-receipt', method: 'GET', path: '/api/v3/x402/receipts/:requestId', canonicalSdkRoute: 'x402.receipt', disposition: 'unavailable', readOnly: true, deploymentRequired: true, responseSchema: `${SCHEMA_ROOT}receipt-status.v1.schema.json`, responseStatuses: [200, 400, 404, 503], description: 'Durable receipt status lookup; no in-memory production fallback.' },
  { id: 'solana-health', method: 'GET', path: '/api/v3/solana/health', canonicalSdkRoute: null, disposition: 'degraded', readOnly: true, deploymentRequired: false, responseSchema: `${SCHEMA_ROOT}solana-health.v1.schema.json`, responseStatuses: [200, 503], description: 'Source and executable evidence health without contacting Solana.' },
  { id: 'retired-partnership-write', method: 'POST', path: '/api/v3/x402/actions/create-partnership-bond', canonicalSdkRoute: null, disposition: 'retired', readOnly: true, deploymentRequired: false, responseSchema: `${SCHEMA_ROOT}retirement.v1.schema.json`, responseStatuses: [503], description: 'Non-executing retirement response retained for explicit safety.' },
] satisfies V3ApiRoute[]);

export function assertV3ApiRouteInventory(value: unknown): asserts value is readonly V3ApiRoute[] {
  if (!Array.isArray(value) || value.length !== 20) throw new Error('V3 inventory must contain exactly 20 routes');
  const ids = new Set<string>();
  const identities = new Set<string>();
  for (const candidate of value) {
    if (!candidate || typeof candidate !== 'object') throw new Error('invalid V3 route');
    const route = candidate as V3ApiRoute;
    if (!route.id || ids.has(route.id) || !['GET', 'POST'].includes(route.method) || !route.path.startsWith('/api/v3/') || route.path.includes('?') || !['supported', 'degraded', 'unavailable', 'retired'].includes(route.disposition) || route.readOnly !== true || !route.responseSchema.startsWith(SCHEMA_ROOT) || !route.responseStatuses.length || !route.description) throw new Error(`invalid V3 route inventory item: ${route.id}`);
    const identity = `${route.method} ${route.path}`;
    if (identities.has(identity)) throw new Error(`duplicate V3 route: ${identity}`);
    ids.add(route.id); identities.add(identity);
  }
}
assertV3ApiRouteInventory(V3_API_ROUTES);
