#!/usr/bin/env npx tsx
/**
 * Orchestrate the full seed pipeline for StemeDB demo.
 *
 * This script:
 * 1. Waits for API health
 * 2. Runs whitepaper seed script
 * 3. Runs external sources seed script
 * 4. Verifies key claims via SkepticLens
 *
 * Usage:
 *   npx tsx scripts/seed-all.ts
 *   npx tsx scripts/seed-all.ts --dry-run
 *   npx tsx scripts/seed-all.ts --verify-only
 *
 * Environment:
 *   STEMEDB_API_URL - API base URL (default: http://127.0.0.1:18180)
 */

import { execSync } from "child_process";

const API_URL = process.env.STEMEDB_API_URL || "http://127.0.0.1:18180";

// ============================================================================
// Types
// ============================================================================

interface SkepticResponse {
  subject: string;
  predicate: string;
  status: "Unanimous" | "Agreed" | "Contested";
  conflict_score: number;
  claims: Array<{
    value: { type: string; value: string | number | boolean };
    weight_share: number;
    assertion_count: number;
  }>;
  candidates_count: number;
}

// ============================================================================
// Health Check
// ============================================================================

async function waitForHealth(maxRetries = 30, delayMs = 2000): Promise<boolean> {
  console.log(`Waiting for API at ${API_URL}...`);

  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(`${API_URL}/v1/health`);
      if (response.ok) {
        const data = await response.json();
        console.log(`API is healthy: v${data.version}, ${data.assertions_count} assertions`);
        return true;
      }
    } catch {
      // Retry
    }

    if (i < maxRetries - 1) {
      console.log(`  Retry ${i + 1}/${maxRetries}...`);
      await new Promise((resolve) => setTimeout(resolve, delayMs));
    }
  }

  console.error(`API not healthy after ${maxRetries} retries`);
  return false;
}

// ============================================================================
// Verification
// ============================================================================

interface VerificationTarget {
  subject: string;
  predicate: string;
  expectedStatus?: "Unanimous" | "Agreed" | "Contested";
  description: string;
}

const VERIFICATION_TARGETS: VerificationTarget[] = [
  // Core StemeDB claims
  {
    subject: "StemeDB",
    predicate: "hash_algorithm",
    expectedStatus: "Unanimous",
    description: "BLAKE3 hash algorithm",
  },
  {
    subject: "StemeDB",
    predicate: "storage_model",
    expectedStatus: "Agreed",
    description: "Append-only Merkle DAG",
  },
  {
    subject: "RecencyLens",
    predicate: "time_complexity",
    expectedStatus: "Unanimous",
    description: "O(n) complexity",
  },

  // Cryptography claims
  {
    subject: "BLAKE3",
    predicate: "output_size",
    expectedStatus: "Unanimous",
    description: "256-bit output",
  },
  {
    subject: "Ed25519",
    predicate: "signature_size",
    expectedStatus: "Unanimous",
    description: "64 bytes",
  },

  // Potential conflicts
  {
    subject: "CRDT",
    predicate: "preserves_disagreement",
    description: "CRDT disagreement preservation (potential conflict)",
  },
  {
    subject: "PostgreSQL",
    predicate: "conflict_resolution",
    description: "PostgreSQL conflict handling (potential conflict)",
  },
  {
    subject: "EigenTrust",
    predicate: "initial_trust_score",
    description: "Trust score initialization (potential conflict)",
  },

  // Database comparisons
  {
    subject: "PostgreSQL",
    predicate: "storage_model",
    description: "PostgreSQL storage model",
  },
  {
    subject: "MongoDB",
    predicate: "storage_model",
    description: "MongoDB storage model",
  },
];

async function verifySkeptic(target: VerificationTarget): Promise<boolean> {
  const url = `${API_URL}/v1/skeptic?subject=${encodeURIComponent(target.subject)}&predicate=${encodeURIComponent(target.predicate)}&include_source_metadata=true`;

  try {
    const response = await fetch(url);
    if (!response.ok) {
      console.log(`  [SKIP] ${target.subject}/${target.predicate}: No data`);
      return true; // Not a failure, just no data
    }

    const data: SkepticResponse = await response.json();
    const statusIcon =
      data.status === "Unanimous" ? "[UNANIMOUS]" :
      data.status === "Agreed" ? "[AGREED]  " :
      "[CONTESTED]";

    const expectedMatch = !target.expectedStatus || data.status === target.expectedStatus;
    const icon = expectedMatch ? "OK" : "!!";

    console.log(
      `  [${icon}] ${statusIcon} ${target.subject}/${target.predicate}: ` +
      `${data.claims.length} claims, conflict=${data.conflict_score.toFixed(2)}`
    );

    if (data.claims.length > 0) {
      const topClaim = data.claims[0];
      console.log(`      Top: "${String(topClaim.value.value).slice(0, 40)}..." (${(topClaim.weight_share * 100).toFixed(0)}%)`);
    }

    return expectedMatch;
  } catch (error) {
    console.error(`  [ERR] ${target.subject}/${target.predicate}: ${error}`);
    return false;
  }
}

async function runVerification(): Promise<boolean> {
  console.log("\n=== Verification via SkepticLens ===\n");

  let passed = 0;
  let failed = 0;
  let skipped = 0;

  for (const target of VERIFICATION_TARGETS) {
    const result = await verifySkeptic(target);
    if (result) {
      passed++;
    } else {
      failed++;
    }
  }

  console.log(`\nVerification: ${passed} passed, ${failed} failed, ${skipped} skipped`);
  return failed === 0;
}

// ============================================================================
// Script Execution
// ============================================================================

function runScript(scriptName: string, dryRun: boolean): void {
  const args = dryRun ? "--dry-run" : "";
  const command = `npx tsx scripts/${scriptName} ${args}`;

  console.log(`\n${"=".repeat(60)}`);
  console.log(`Running: ${scriptName}${dryRun ? " (dry run)" : ""}`);
  console.log("=".repeat(60) + "\n");

  try {
    execSync(command, {
      stdio: "inherit",
      cwd: process.cwd(),
      env: { ...process.env, STEMEDB_API_URL: API_URL },
    });
  } catch (error) {
    console.error(`Script ${scriptName} failed:`, error);
    throw error;
  }
}

// ============================================================================
// Main
// ============================================================================

async function main(): Promise<void> {
  const args = process.argv.slice(2);
  const dryRun = args.includes("--dry-run") || args.includes("-d");
  const verifyOnly = args.includes("--verify-only") || args.includes("-v");

  console.log("StemeDB Full Seed Pipeline");
  console.log("==========================");
  console.log(`API URL: ${API_URL}`);
  if (dryRun) console.log("Mode: DRY RUN");
  if (verifyOnly) console.log("Mode: VERIFY ONLY");
  console.log();

  // Health check
  const healthy = await waitForHealth();
  if (!healthy) {
    console.error("\nAPI is not available. Please start stemedb-api first:");
    console.error("  cargo run --bin stemedb-api");
    process.exit(1);
  }
  console.log();

  if (!verifyOnly) {
    // Phase 1: Whitepaper claims
    runScript("seed-whitepaper.ts", dryRun);

    // Phase 2: External sources
    runScript("seed-external.ts", dryRun);

    if (!dryRun) {
      // Wait for materialization
      console.log("\nWaiting for final materialization...");
      await new Promise((resolve) => setTimeout(resolve, 3000));
    }
  }

  // Phase 3: Verification
  if (!dryRun) {
    const verificationPassed = await runVerification();

    if (!verificationPassed) {
      console.warn("\nSome verifications failed. Check the output above.");
    }
  }

  console.log("\n" + "=".repeat(60));
  console.log("Seed pipeline complete!");
  console.log("=".repeat(60));
  console.log("\nNext steps:");
  console.log("  1. Start the community app: cd community && npm run dev");
  console.log("  2. Visit http://localhost:18187");
  console.log("  3. Click on annotated claims to see conflict analysis");
}

main().catch((error) => {
  console.error("Pipeline failed:", error.message);
  process.exit(1);
});
