import { existsSync, readFileSync } from 'fs';
import path from 'path';

export interface OfficialProtocolContractRow {
  name: string;
  address: string;
  inventoryKey?: string;
  minCodeSize?: number;
  notes?: string;
}

export interface OfficialProtocolRow {
  id: string;
  classification?: string;
  requiredForProduction?: boolean;
  upstreamRepo?: string;
  upstreamSubmodule?: string;
  deployScripts?: string[];
  verifyScripts?: string[];
  deployMethod?: string;
  integrationNotes?: string;
  contracts: OfficialProtocolContractRow[];
}

export interface OfficialProtocolsReport {
  generatedAt: string;
  source: string;
  schemaVersion?: string;
  updated?: string;
  chainId: number;
  chainName?: string;
  policyDoc?: string;
  guardrails: string[];
  forbiddenProductionPatterns: Array<{ id: string; description: string }>;
  count: number;
  protocols: OfficialProtocolRow[];
}

function resolveRegistryRoots(): string[] {
  const cwd = process.cwd();
  return [
    ...new Set(
      [
        cwd,
        path.join(cwd, 'smom-dbis-138', 'services', 'token-aggregation'),
        process.env.PROXMOX_REPO_ROOT,
        process.env.PROJECT_ROOT,
        path.resolve(cwd, '..', '..', '..'),
      ].filter(Boolean) as string[],
    ),
  ];
}

function loadRegistryJson(): Record<string, unknown> | null {
  const configured = process.env.CHAIN138_OFFICIAL_PROTOCOL_CONTRACTS_JSON?.trim();
  const candidates = [
    configured,
    ...resolveRegistryRoots().map((root) => path.join(root, 'config/chain138-official-protocol-contracts.json')),
  ].filter(Boolean) as string[];

  for (const candidate of candidates) {
    if (!existsSync(candidate)) continue;
    try {
      return JSON.parse(readFileSync(candidate, 'utf8')) as Record<string, unknown>;
    } catch {
      continue;
    }
  }
  return null;
}

export function buildOfficialProtocolsReport(protocolIdFilter?: string | null): OfficialProtocolsReport | null {
  const raw = loadRegistryJson();
  if (!raw) return null;

  const protocolsRaw = raw.protocols as Record<string, Record<string, unknown>> | undefined;
  const protocols: OfficialProtocolRow[] = [];

  for (const [id, entry] of Object.entries(protocolsRaw ?? {})) {
    if (protocolIdFilter && id !== protocolIdFilter) continue;
    const contractsRaw = entry.contracts as Record<string, Record<string, unknown>> | undefined;
    const contracts: OfficialProtocolContractRow[] = Object.entries(contractsRaw ?? {}).map(([name, row]) => ({
      name,
      address: String(row.address ?? ''),
      inventoryKey: typeof row.inventoryKey === 'string' ? row.inventoryKey : undefined,
      minCodeSize: typeof row.minCodeSize === 'number' ? row.minCodeSize : undefined,
      notes: typeof row.notes === 'string' ? row.notes : undefined,
    }));

    protocols.push({
      id,
      classification: typeof entry.classification === 'string' ? entry.classification : undefined,
      requiredForProduction: entry.requiredForProduction === true,
      upstreamRepo: typeof entry.upstreamRepo === 'string' ? entry.upstreamRepo : undefined,
      upstreamSubmodule: typeof entry.upstreamSubmodule === 'string' ? entry.upstreamSubmodule : undefined,
      deployScripts: Array.isArray(entry.deployScripts) ? (entry.deployScripts as string[]) : undefined,
      verifyScripts: Array.isArray(entry.verifyScripts) ? (entry.verifyScripts as string[]) : undefined,
      deployMethod: typeof entry.deployMethod === 'string' ? entry.deployMethod : undefined,
      integrationNotes: typeof entry.integrationNotes === 'string' ? entry.integrationNotes : undefined,
      contracts,
    });
  }

  protocols.sort((left, right) => left.id.localeCompare(right.id));

  return {
    generatedAt: new Date().toISOString(),
    source: 'config/chain138-official-protocol-contracts.json',
    schemaVersion: typeof raw.schemaVersion === 'string' ? raw.schemaVersion : undefined,
    updated: typeof raw.updated === 'string' ? raw.updated : undefined,
    chainId: Number(raw.chainId ?? 138),
    chainName: typeof raw.chainName === 'string' ? raw.chainName : undefined,
    policyDoc: typeof raw.policyDoc === 'string' ? raw.policyDoc : undefined,
    guardrails: Array.isArray(raw.guardrails) ? (raw.guardrails as string[]) : [],
    forbiddenProductionPatterns: Array.isArray(raw.forbiddenProductionPatterns)
      ? (raw.forbiddenProductionPatterns as Array<{ id: string; description: string }>)
      : [],
    count: protocols.length,
    protocols,
  };
}
