/**
 * SKILLS.md writer and parser for the Pipeline Skill Advisor.
 * Generates markdown output and parses it back for round-trip fidelity.
 */

import type { ContentMatchResult, SkillMatch, SkillMatchTier } from './content-matcher-types.js';

// ---------------------------------------------------------------------------
// Generator
// ---------------------------------------------------------------------------

/**
 * Generate a SKILLS.md markdown string from match results.
 *
 * @param featureName - Human-readable feature name for the heading
 * @param result - Content match result with scored skill matches
 * @param totalSkillCount - Optional total skills scanned (for footer stats)
 */
export function generateSkillsMd(
  featureName: string,
  result: ContentMatchResult,
  totalSkillCount?: number
): string {
  const lines: string[] = [];

  lines.push(`# Recommended Skills: ${featureName}`);
  lines.push('');
  lines.push('> Auto-generated by Pipeline Skill Advisor. Review and adjust as needed.');

  const apply = result.matches.filter((m) => m.tier === 'apply');
  const reference = result.matches.filter((m) => m.tier === 'reference');
  const consider = result.matches.filter((m) => m.tier === 'consider');

  if (apply.length > 0) {
    lines.push('');
    lines.push('## Apply (invoke during execution)');
    lines.push('');
    lines.push(...renderTable(apply));
  }

  if (reference.length > 0) {
    lines.push('');
    lines.push('## Reference (load as context)');
    lines.push('');
    lines.push(...renderTable(reference));
  }

  if (consider.length > 0) {
    lines.push('');
    lines.push('## Consider');
    lines.push('');
    lines.push(...renderTable(consider));
  }

  lines.push('');
  lines.push('---');
  const skillsScanned = totalSkillCount ?? result.matches.length;
  const keywords = result.signalsUsed.specKeywords.length;
  const stack = result.signalsUsed.stackSignals.length;
  const domains = result.signalsUsed.featureDomain.length;
  lines.push(
    `*Scanned ${skillsScanned} skills in ${result.scanDuration}ms. Signals: ${keywords} keywords, ${stack} stack markers, ${domains} domains.*`
  );
  lines.push('');

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

function renderTable(matches: SkillMatch[]): string[] {
  const lines: string[] = [];
  lines.push('| Skill | Purpose | When | Relevance |');
  lines.push('|-------|---------|------|-----------|');
  for (const match of matches) {
    const purpose = match.matchReasons.join('; ');
    lines.push(`| \`${match.skillName}\` | ${purpose} | ${match.when} | ${match.score} |`);
  }
  return lines;
}

// ---------------------------------------------------------------------------
// Parser
// ---------------------------------------------------------------------------

const TIER_HEADING_MAP: Array<[RegExp, SkillMatchTier]> = [
  [/^## Apply/i, 'apply'],
  [/^## Reference/i, 'reference'],
  [/^## Consider/i, 'consider'],
];

/** Detect whether a line is a tier heading and return the tier if so. */
function detectTier(line: string): SkillMatchTier | undefined {
  for (const [pattern, tier] of TIER_HEADING_MAP) {
    if (pattern.test(line)) return tier;
  }
  return undefined;
}

/** Parse a single table row into a SkillMatch, or return undefined if it cannot be parsed. */
function parseTableRow(line: string, tier: SkillMatchTier): SkillMatch | undefined {
  const cells = line
    .split('|')
    .map((c) => c.trim())
    .filter((c) => c.length > 0);

  if (cells.length < 4) return undefined;

  const score = parseFloat(cells[3]!);
  if (isNaN(score)) return undefined;

  return {
    skillName: cells[0]!.replace(/`/g, ''),
    score,
    tier,
    matchReasons: [cells[1]!],
    category: '',
    when: cells[2]!,
  };
}

/**
 * Parse a SKILLS.md markdown string back into SkillMatch objects.
 * Used for loading previously generated recommendations.
 */
export function parseSkillsMd(markdown: string): SkillMatch[] {
  if (!markdown || !markdown.includes('# Recommended Skills:')) return [];

  const lines = markdown.split('\n');
  const matches: SkillMatch[] = [];
  let currentTier: SkillMatchTier | null = null;

  for (const line of lines) {
    const tier = detectTier(line);
    if (tier) {
      currentTier = tier;
      continue;
    }

    if (!currentTier || !line.startsWith('| `')) continue;

    const match = parseTableRow(line, currentTier);
    if (match) matches.push(match);
  }

  return matches;
}
