#!/usr/bin/env node

import { readFile, readdir } from "node:fs/promises";
import path from "node:path";
import { ownerEvidenceToolPolicy } from "../src/adapters/ownerEvidenceTools.js";

const rootDir = process.cwd();
const runId = argValue("--runId") || argValue("--run-id") || "current";
const run = await loadRun(runId);
const counters = run.counters || {};
const rejected = Array.isArray(run.rejectedLeads) ? run.rejectedLeads : [];
const toolAttempts = Array.isArray(run.ownerEvidenceToolAttempts) ? run.ownerEvidenceToolAttempts : [];
const websiteToolPolicy = ownerEvidenceToolPolicy(run, { mode: "website" });
const profileToolPolicy = ownerEvidenceToolPolicy(run, { mode: "profiles" });

const output = {
  run: {
    id: run.id,
    status: run.status,
    niche: run.input?.niche,
    target: run.input?.target,
    updatedAt: run.updatedAt
  },
  funnel: {
    discovered: counters.discovered || run.discoveredLeads?.length || 0,
    ownerHunts: counters.ownerRabbitHoles || 0,
    ownerProfilesFound: counters.ownerProfilesFound || 0,
    ownerContactsFound: counters.ownerContactsFound || 0,
    ownerSeedRejections: counters.ownerSeedRejections || 0,
    franchiseRejections: counters.franchiseRejections || 0,
    ownerIdentityGateRejections: counters.ownerIdentityGateRejections || 0,
    ownerAgentsStarted: counters.ownerAgentsStarted || 0,
    ownerAgentsDeployed: counters.ownerAgentsDeployed || 0,
    ownerAgentsTimedOut: counters.ownerAgentsTimedOut || 0,
    ownerAgentSearchHits: counters.ownerAgentSearchHits || 0,
    ownerAgentPagesFetched: counters.ownerAgentPagesFetched || 0,
    ownerAgentContactPromotions: counters.ownerAgentContactPromotions || 0,
    llmCalls: counters.llmCalls || 0,
    llmTimeouts: counters.llmTimeouts || 0
  },
  yield: {
    ownerProfileYieldPercent: percent(counters.ownerProfilesFound, counters.ownerRabbitHoles),
    ownerContactYieldPercent: percent(counters.ownerContactsFound, counters.ownerRabbitHoles),
    searchHitFetchPercent: percent(counters.ownerAgentPagesFetched, counters.ownerAgentSearchHits),
    timeoutPercent: percent(counters.ownerAgentsTimedOut, counters.ownerAgentsStarted)
  },
  rejectedStatuses: countBy(rejected, (lead) => lead.rabbitHoleStatus || lead.ownerHuntStatus || "unknown"),
  ownerNamesFound: rejected
    .filter((lead) => lead.ownerName)
    .slice(0, 20)
    .map((lead) => ({
      name: lead.name,
      city: lead.city,
      ownerName: lead.ownerName,
      ownerEvidenceUrl: lead.ownerEvidenceUrl,
      rabbitHoleStatus: lead.rabbitHoleStatus,
      ownerEmail: lead.ownerEmail,
      ownerPhone: lead.ownerPhone
    })),
  toolAttempts: summarizeToolAttempts(toolAttempts),
  toolPolicy: {
    website: websiteToolPolicy,
    profiles: profileToolPolicy
  },
  recommendations: recommendations({ counters, rejected, toolAttempts, toolPolicies: [websiteToolPolicy, profileToolPolicy] })
};

console.log(JSON.stringify(output, null, 2));

function argValue(name) {
  const direct = process.argv.find((arg) => arg.startsWith(`${name}=`));
  if (direct) return direct.slice(name.length + 1);
  const index = process.argv.indexOf(name);
  return index >= 0 ? process.argv[index + 1] || "" : "";
}

async function loadRun(id) {
  const runsDir = path.join(rootDir, "data", "runs");
  if (id && id !== "current") {
    return JSON.parse(await readFile(path.join(runsDir, `${id}.json`), "utf8"));
  }
  const files = (await readdir(runsDir))
    .filter((file) => file.endsWith(".json"))
    .map((file) => path.join(runsDir, file));
  const runs = [];
  for (const file of files) {
    try {
      const run = JSON.parse(await readFile(file, "utf8"));
      runs.push(run);
    } catch {
      continue;
    }
  }
  runs.sort((a, b) => String(b.updatedAt || b.createdAt).localeCompare(String(a.updatedAt || a.createdAt)));
  const active = runs.find((run) => ["queued", "running"].includes(run.status));
  return active || runs[0] || {};
}

function summarizeToolAttempts(attempts = []) {
  const rows = [];
  for (const attempt of attempts) {
    for (const tool of attempt.toolAttempts || []) {
      rows.push({
        tool: tool.tool,
        status: tool.status,
        timeout: Boolean(tool.timeout),
        error: tool.error || tool.reason || ""
      });
    }
  }
  return Object.values(rows.reduce((acc, row) => {
    const key = `${row.tool}:${row.status}:timeout=${row.timeout}`;
    acc[key] ||= { ...row, count: 0 };
    acc[key].count += 1;
    return acc;
  }, {}));
}

function recommendations({ counters, rejected, toolAttempts, toolPolicies = [] }) {
  const out = [];
  if ((counters.ownerContactsFound || 0) === 0 && (counters.ownerRabbitHoles || 0) >= 10) {
    out.push("Owner-contact yield is zero after many hunts; use owner-first seed queries and keep strict proof gating.");
  }
  if ((counters.ownerIdentityGateRejections || 0) > 0) {
    out.push("Identity gate is skipping direct contact swarms without a named owner; this is expected and saves budget.");
  }
  if ((counters.ownerAgentsTimedOut || 0) > (counters.ownerAgentsStarted || 1) * 0.4) {
    out.push("Owner-agent timeout rate is high; lower swarm size or reduce owner search result limits before scaling.");
  }
  if (toolAttempts.some((attempt) => (attempt.toolAttempts || []).some((tool) => tool.timeout))) {
    out.push("At least one owner-evidence tool is timing out; inspect toolkit probe and keep Photon/Scrapling paths as primary.");
  }
  for (const policy of toolPolicies) {
    if (policy.disabledTools?.length) {
      out.push(`Owner-evidence timeout policy will skip ${policy.disabledTools.join(", ")} and continue with public-profile/Scrapling paths.`);
    }
  }
  if (rejected.some((lead) => /chain|franchise|multi-location/i.test(lead.reason || lead.ownerHuntDecision || ""))) {
    out.push("Chain/franchise seeds are being rejected early; use independent/owner-operated keyword expansion for better yield.");
  }
  return out;
}

function countBy(items, keyFn) {
  return items.reduce((acc, item) => {
    const key = keyFn(item);
    acc[key] = (acc[key] || 0) + 1;
    return acc;
  }, {});
}

function percent(numerator, denominator) {
  const top = Number(numerator || 0);
  const bottom = Number(denominator || 0);
  return bottom ? Math.round((top / bottom) * 1000) / 10 : 0;
}
