/*
 * escalate-low-traffic — opens a separate traffic issue when URLs are
 * indexed but still earning no impressions after the T+14 window.
 *
 * Usage:
 *   tsx escalate-low-traffic.ts [--state file.json] [--out file.json] [--min-age-days 14]
 */
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import { type BlogIndexingState, BLOG_DIR, REPO_ROOT, slugFromUrl } from './lib.ts';

interface Args {
  state: string;
  out?: string;
  minAgeDays: number;
}

function parseArgs(argv: string[]): Args {
  const args: Partial<Args> = {};
  for (let i = 0; i < argv.length; i++) {
    if (argv[i] === '--state') args.state = argv[++i];
    else if (argv[i] === '--out') args.out = argv[++i];
    else if (argv[i] === '--min-age-days') args.minAgeDays = Number(argv[++i]);
  }
  args.state ??= path.join(REPO_ROOT, 'docs/blog-indexing-status.json');
  args.minAgeDays ??= 14;
  return args as Args;
}

function ageDays(firstInspectedAt?: string): number {
  if (!firstInspectedAt) return 0;
  const since = new Date(firstInspectedAt).getTime();
  return Math.floor((Date.now() - since) / 86_400_000);
}

function frontmatterDate(slug: string): string | null {
  const file = path.join(BLOG_DIR, `${slug}.md`);
  if (!existsSync(file)) return null;
  const raw = readFileSync(file, 'utf8');
  return raw.match(/^---\n[\s\S]*?\ndate:\s*([0-9]{4}-[0-9]{2}-[0-9]{2})\b/m)?.[1] ?? null;
}

function ageDaysFromDate(date: string): number {
  return Math.floor((Date.now() - new Date(`${date}T00:00:00Z`).getTime()) / 86_400_000);
}

function main() {
  const { state: stateFile, out, minAgeDays } = parseArgs(process.argv.slice(2));
  const state: BlogIndexingState = existsSync(stateFile)
    ? JSON.parse(readFileSync(stateFile, 'utf8'))
    : { latest: {}, history: [] };
  const lowTraffic: Array<{
    url: string;
    slug: string;
    ageDays: number;
    impressions7d: number;
    impressions28d: number;
    clicks28d: number;
    position28d: number;
  }> = [];

  for (const [url, record] of Object.entries(state.latest ?? {})) {
    if ('error' in record.result || !record.result.isIndexed) continue;
    const slug = slugFromUrl(url);
    const publishedAt = frontmatterDate(slug);
    const firstInspectedAt =
      state.firstInspectedAt?.[url] ?? state.firstSeenAt?.[url];
    const age = publishedAt
      ? ageDaysFromDate(publishedAt)
      : ageDays(firstInspectedAt);
    if (age < minAgeDays) continue;
    const perf7 = state.performance?.[url]?.['7'];
    const perf28 = state.performance?.[url]?.['28'];
    const impressions7d = perf7?.impressions ?? 0;
    const impressions28d = perf28?.impressions ?? 0;
    if (impressions7d > 0 || impressions28d > 0) continue;
    lowTraffic.push({
      url,
      slug,
      ageDays: age,
      impressions7d,
      impressions28d,
      clicks28d: perf28?.clicks ?? 0,
      position28d: perf28?.position ?? 0,
    });
  }

  const issueTitle = 'Blog traffic — indexed posts with zero impressions';
  const issueBody = lowTraffic.length
    ? [
        'The daily blog monitor found posts that are indexed but still have zero Google Search impressions after the T+14 window.',
        '',
        '| URL | Age (days) | 7d impressions | 28d impressions | 28d clicks | 28d avg position |',
        '|---|---:|---:|---:|---:|---:|',
        ...lowTraffic.map(
          (p) =>
            `| ${p.url} | ${p.ageDays} | ${p.impressions7d} | ${p.impressions28d} | ${p.clicks28d} | ${p.position28d || '—'} |`,
        ),
        '',
        'This is not an indexing bug. Treat it as a distribution / query-fit issue:',
        '',
        '1. Re-check title and summary against the target query.',
        '2. Add internal links from `/blog/` and the closest related posts.',
        '3. Consider cross-posting with canonical URL back to Open Design.',
        '4. Re-score the topic in `_topics.md` if it still has zero impressions after 28 days.',
        '',
        'This issue is generated by `.github/workflows/blog-indexing-monitor.yml`.',
      ].join('\n')
    : '';

  const result = {
    shouldEscalate: lowTraffic.length > 0,
    lowTraffic,
    issueTitle,
    issueBody,
  };
  const json = JSON.stringify(result, null, 2);
  if (out) writeFileSync(out, json + '\n');
  else process.stdout.write(json + '\n');
}

main();
