/**
 * Output rendering for the CLI and library consumers.
 *
 * Three formats are supported: a terminal-friendly `table` (default),
 * a structured `json` blob, and a `markdown` block suitable for
 * embedding in status updates or weekly digests.
 */

import type { FetchedStats } from './github.js';
import type { RepoStats } from './types.js';
import type { RepoSummary } from './summary.js';

export type { FetchedStats, RepoStats };

export type RenderFormat = 'table' | 'json' | 'markdown';

function pad(s: string | number, width: number, align: 'left' | 'right' = 'left'): string {
  const str = String(s);
  if (str.length >= width) return str;
  const fill = ' '.repeat(width - str.length);
  return align === 'left' ? str + fill : fill + str;
}

function truncate(s: string, max: number): string {
  if (s.length <= max) return s;
  return s.slice(0, max - 1) + '…';
}

function fmtDate(iso: string | null): string {
  if (!iso) return '—';
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return iso;
  return d.toISOString().slice(0, 10);
}

function fmtNum(n: number): string {
  if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M';
  if (n >= 1_000) return (n / 1_000).toFixed(1) + 'k';
  return String(n);
}

export function renderJson(fetched: FetchedStats): string {
  return JSON.stringify(fetched, null, 2) + '\n';
}

export function renderMarkdown(summary: RepoSummary): string {
  const r = summary.fetched.repo;
  const lines: string[] = [];
  lines.push(`# ${r.repo.owner}/${r.repo.name}`);
  if (r.description) lines.push(`> ${r.description}`);
  lines.push('');
  lines.push(`- **Stars:** ${fmtNum(r.stars)}  `);
  lines.push(`- **Forks:** ${fmtNum(r.forks)}  `);
  lines.push(`- **Watchers:** ${fmtNum(r.watchers)}  `);
  if (r.primaryLanguage) lines.push(`- **Language:** ${r.primaryLanguage}  `);
  if (r.license) lines.push(`- **License:** ${r.license}  `);
  lines.push(`- **Last push:** ${fmtDate(r.pushedAt)}  `);
  lines.push('');
  lines.push('## Activity');
  lines.push('');
  lines.push(`- Issues: ${summary.issues.open} open / ${summary.issues.closed} closed`);
  lines.push(`- Last 7d issues: ${summary.issues.last7d.total} (${summary.issues.last7d.open} open, ${summary.issues.last7d.closed} closed)`);
  lines.push(`- Pull requests: ${summary.pulls.open} open / ${summary.pulls.merged} merged / ${summary.pulls.closed} closed`);
  lines.push(`- Last 7d PRs: ${summary.pulls.last7d.opened} opened, ${summary.pulls.last7d.merged} merged`);
  if (summary.releases.latest) {
    lines.push(`- Latest release: ${summary.releases.latest.tagName} (${fmtDate(summary.releases.latest.publishedAt)})`);
    if (summary.releases.cadenceDays !== null) {
      lines.push(`- Release cadence: every ${summary.releases.cadenceDays} days`);
    }
  }
  if (summary.issues.topLabels.length > 0) {
    lines.push('');
    lines.push('### Top issue labels');
    for (const l of summary.issues.topLabels) {
      lines.push(`- ${l.label}: ${l.count}`);
    }
  }
  if (summary.contributors.top.length > 0) {
    lines.push('');
    lines.push('### Top contributors');
    for (const c of summary.contributors.top) {
      lines.push(`- @${c.login} (${c.contributions})`);
    }
  }
  return lines.join('\n') + '\n';
}

/**
 * Render a terminal-friendly table. We intentionally avoid pulling in
 * any table-rendering dependency: the layout is fixed-width and we
 * truncate long titles so the output stays readable on 80-col terminals.
 */
export function renderTable(summary: RepoSummary): string {
  const r = summary.fetched.repo;
  const lines: string[] = [];
  lines.push('');
  lines.push(`${r.repo.owner}/${r.repo.name}`);
  if (r.description) lines.push(r.description);
  lines.push('');
  lines.push('Repository');
  lines.push(`  stars:        ${fmtNum(r.stars)}`);
  lines.push(`  forks:        ${fmtNum(r.forks)}`);
  lines.push(`  watchers:     ${fmtNum(r.watchers)}`);
  lines.push(`  open issues:  ${r.openIssues}`);
  if (r.primaryLanguage) lines.push(`  language:     ${r.primaryLanguage}`);
  if (r.license) lines.push(`  license:      ${r.license}`);
  lines.push(`  size:         ${(r.sizeKb / 1024).toFixed(2)} MB`);
  lines.push(`  default:      ${r.defaultBranch}`);
  lines.push(`  created:      ${fmtDate(r.createdAt)}`);
  lines.push(`  last push:    ${fmtDate(r.pushedAt)}`);
  if (r.archived) lines.push(`  archived:     yes`);
  if (r.topics.length > 0) lines.push(`  topics:       ${r.topics.join(', ')}`);

  lines.push('');
  lines.push('Issues');
  lines.push(`  open:         ${summary.issues.open}`);
  lines.push(`  closed:       ${summary.issues.closed}`);
  lines.push(`  last 7d:      ${summary.issues.last7d.total} (${summary.issues.last7d.open} open, ${summary.issues.last7d.closed} closed)`);
  lines.push(`  last 30d:     ${summary.issues.last30d.total} (${summary.issues.last30d.open} open, ${summary.issues.last30d.closed} closed)`);
  if (summary.issues.topLabels.length > 0) {
    lines.push(`  top labels:   ${summary.issues.topLabels.map((l) => `${l.label} (${l.count})`).join(', ')}`);
  }
  if (summary.fetched.issues.length > 0) {
    lines.push('');
    lines.push(`  recent issues (${Math.min(5, summary.fetched.issues.length)}):`);
    for (const i of summary.fetched.issues.slice(0, 5)) {
      lines.push(`    #${i.number} [${i.state}] ${truncate(i.title, 60)}  (@${i.user})`);
    }
  }

  lines.push('');
  lines.push('Pull Requests');
  lines.push(`  open:         ${summary.pulls.open}`);
  lines.push(`  merged:       ${summary.pulls.merged}`);
  lines.push(`  closed:       ${summary.pulls.closed}`);
  lines.push(`  last 7d:      ${summary.pulls.last7d.opened} opened, ${summary.pulls.last7d.merged} merged`);
  lines.push(`  last 30d:     ${summary.pulls.last30d.opened} opened, ${summary.pulls.last30d.merged} merged`);
  if (summary.pulls.avgChangedFiles > 0) {
    lines.push(`  avg files/PR: ${summary.pulls.avgChangedFiles}`);
  }
  if (summary.fetched.pulls.length > 0) {
    lines.push('');
    lines.push(`  recent PRs (${Math.min(5, summary.fetched.pulls.length)}):`);
    for (const p of summary.fetched.pulls.slice(0, 5)) {
      const tag = p.state === 'merged' ? 'merged' : p.state;
      const delta =
        p.additions > 0 || p.deletions > 0 ? ` (+${p.additions}/-${p.deletions})` : '';
      lines.push(`    #${p.number} [${tag}] ${truncate(p.title, 60)}  (@${p.user})${delta}`);
    }
  }

  if (summary.fetched.releases.length > 0) {
    lines.push('');
    lines.push('Releases');
    lines.push(`  total:        ${summary.releases.total}`);
    if (summary.releases.latest) {
      lines.push(`  latest:       ${summary.releases.latest.tagName} (${fmtDate(summary.releases.latest.publishedAt)})`);
    }
    if (summary.releases.cadenceDays !== null) {
      lines.push(`  cadence:      every ${summary.releases.cadenceDays} days`);
    }
    for (const rel of summary.fetched.releases.slice(0, 5)) {
      lines.push(`    ${rel.tagName}${rel.prerelease ? ' (pre)' : ''} — ${fmtDate(rel.publishedAt)}`);
    }
  }

  if (summary.fetched.contributors.length > 0) {
    lines.push('');
    lines.push('Contributors (top 5)');
    for (const c of summary.contributors.top) {
      lines.push(`  @${pad(c.login, 25)}  ${c.contributions} contributions`);
    }
  }

  lines.push('');
  return lines.join('\n');
}
