import { writeFileSync } from 'node:fs';
import { readArgValue } from './cli-arg-lib.mjs';
import { createReleasePlan, getRepoRoot, listPublicPackages, loadPackageRetirements, loadPackageSurface } from './package-surface-lib.mjs';
import { readNpmAuthState } from './npm-surface-lib.mjs';

const rawArgs = process.argv.slice(2);
const args = new Set(rawArgs);
const jsonOutput = args.has('--json');
const reportJsonValue = readArgValue(rawArgs, 'report-json');
const summaryMarkdownValue = readArgValue(rawArgs, 'summary-markdown');
const onlySupport = readArgValue(rawArgs, 'support');
const onlyWave = readArgValue(rawArgs, 'wave');
const onlyNames = new Set(
  readArgValue(rawArgs, 'only')
    ? readArgValue(rawArgs, 'only')
        .split(',')
        .map((value) => value.trim())
        .filter(Boolean)
    : [],
);

const root = getRepoRoot();
const surface = loadPackageSurface(root);
const retirements = loadPackageRetirements(root);
const publicPackages = listPublicPackages(root);
const plan = createReleasePlan(surface, publicPackages, retirements);
const npmAuth = readNpmAuthState();
const filteredPackages = onlySupport
  ? plan.packages.filter((entry) => entry.support === onlySupport)
  : plan.packages;
const filteredByWave = onlyWave
  ? filteredPackages.filter((entry) => entry.releaseWave === onlyWave)
  : filteredPackages;
const filteredByName = onlyNames.size > 0
  ? filteredByWave.filter((entry) => onlyNames.has(entry.name))
  : filteredByWave;

const output = {
  ...plan,
  npmAuth,
  packages: filteredByName,
  counts: {
    publishLatest: filteredByName.filter((entry) => entry.recommendedAction === 'publish-latest').length,
    publishNext: filteredByName.filter((entry) => entry.recommendedAction === 'publish-next').length,
    holdInternal: filteredByName.filter((entry) => entry.recommendedAction === 'hold-internal').length,
    holdExperimental: filteredByName.filter((entry) => entry.recommendedAction === 'hold-experimental').length,
    retired: filteredByName.filter((entry) => entry.recommendedAction === 'retired').length,
    byWave: filteredByName.reduce((acc, entry) => {
      acc[entry.releaseWave] = (acc[entry.releaseWave] || 0) + 1;
      return acc;
    }, {}),
  },
};

function escapeMarkdownCell(value) {
  let escaped = '';
  for (const char of String(value ?? '-')) {
    if (char === '\\') escaped += '\\\\';
    else if (char === '|') escaped += '\\|';
    else if (char === '\n' || char === '\r') escaped += ' ';
    else escaped += char;
  }
  return escaped;
}

const markdownLines = [
  '# Package Release Plan',
  '',
  `- Generated at: ${output.generatedAt}`,
  `- Packages in scope: ${output.packages.length}`,
  `- Support filter: ${onlySupport ?? 'all'}`,
  `- Release wave filter: ${onlyWave ?? 'all'}`,
  `- Package filter: ${onlyNames.size > 0 ? [...onlyNames].join(', ') : 'all'}`,
  `- npm auth: ${npmAuth.authenticated ? `authenticated${npmAuth.username ? ` as ${npmAuth.username}` : ''}` : 'not authenticated'}`,
  `- Publish latest: ${output.counts.publishLatest}`,
  `- Publish next: ${output.counts.publishNext}`,
  `- Hold internal: ${output.counts.holdInternal}`,
  `- Hold experimental: ${output.counts.holdExperimental}`,
  `- Retired: ${output.counts.retired}`,
  '',
  '## npm Auth',
  '',
  npmAuth.authenticated
    ? `- authenticated${npmAuth.username ? ` as ${npmAuth.username}` : ''}`
    : `- not authenticated: ${npmAuth.error}`,
  '',
  '| Package | Wave | Order | Current version | Stable target | Maturity | Action | Dist-tag | Notes |',
  '| --- | --- | --- | --- | --- | --- | --- | --- | --- |',
  ...output.packages.map((entry) => {
    const note = entry.recommendedAction === 'retired'
      ? (entry.retirement?.replacement ? `Replacement: ${entry.retirement.replacement}` : entry.summary)
      : entry.blockers.length > 0
        ? entry.blockers[0]
        : entry.summary;
    return `| ${entry.name} | ${entry.releaseWave} | ${entry.publishOrder} | ${entry.version ?? '-'} | ${entry.stableTargetVersion ?? '-'} | ${entry.maturity} | ${entry.recommendedAction} | ${entry.releaseTag ?? '-'} | ${escapeMarkdownCell(note)} |`;
  }),
  '',
];
const markdown = `${markdownLines.join('\n')}\n`;

if (reportJsonValue) {
  writeFileSync(reportJsonValue, `${JSON.stringify(output, null, 2)}\n`, 'utf8');
}

if (summaryMarkdownValue) {
  writeFileSync(summaryMarkdownValue, markdown, 'utf8');
}

if (jsonOutput) {
  console.log(JSON.stringify(output, null, 2));
} else {
  console.log(markdown);
}
