// lib/parsers/project-discovery.mjs
// Discover ultra-suite artifacts inside a project directory.
//
// Layout (post-v3.0.0 project-directory contract):
//   .claude/projects/<YYYY-MM-DD>-<slug>/
//     brief.md
//     research/<NN>-<slug>.md (sorted by filename)
//     architecture/overview.md   (opt-in, owned by separate ultra-cc-architect plugin)
//     plan.md
//     progress.json

import { existsSync, readdirSync, statSync } from 'node:fs';
import { join } from 'node:path';

/**
 * @typedef {{
 *   projectDir: string,
 *   brief: string|null,
 *   research: string[],
 *   architecture: { overview: string|null, gaps: string|null, looseFiles: string[] },
 *   plan: string|null,
 *   progress: string|null,
 *   review: string|null,
 * }} ProjectArtifacts
 */

/** @returns {ProjectArtifacts} */
export function discoverProject(projectDir) {
  const out = {
    projectDir,
    brief: null,
    research: [],
    architecture: { overview: null, gaps: null, looseFiles: [] },
    plan: null,
    progress: null,
    review: null,
  };

  if (!projectDir || !existsSync(projectDir) || !statSync(projectDir).isDirectory()) {
    return out;
  }

  const briefPath = join(projectDir, 'brief.md');
  if (existsSync(briefPath) && statSync(briefPath).isFile()) out.brief = briefPath;

  const planPath = join(projectDir, 'plan.md');
  if (existsSync(planPath) && statSync(planPath).isFile()) out.plan = planPath;

  const progressPath = join(projectDir, 'progress.json');
  if (existsSync(progressPath) && statSync(progressPath).isFile()) out.progress = progressPath;

  const reviewPath = join(projectDir, 'review.md');
  if (existsSync(reviewPath) && statSync(reviewPath).isFile()) out.review = reviewPath;

  const researchDir = join(projectDir, 'research');
  if (existsSync(researchDir) && statSync(researchDir).isDirectory()) {
    out.research = readdirSync(researchDir)
      .filter(f => f.endsWith('.md'))
      .sort()
      .map(f => join(researchDir, f));
  }

  const archDir = join(projectDir, 'architecture');
  if (existsSync(archDir) && statSync(archDir).isDirectory()) {
    const overviewPath = join(archDir, 'overview.md');
    const gapsPath = join(archDir, 'gaps.md');
    if (existsSync(overviewPath)) out.architecture.overview = overviewPath;
    if (existsSync(gapsPath)) out.architecture.gaps = gapsPath;
    const all = readdirSync(archDir).filter(f => f.endsWith('.md'));
    out.architecture.looseFiles = all
      .filter(f => f !== 'overview.md' && f !== 'gaps.md')
      .map(f => join(archDir, f));
  }

  return out;
}

/**
 * Validate that artifact set is consistent for a given pipeline phase.
 * Phase = 'brief' | 'research' | 'plan' | 'execute' | 'review'.
 */
export function checkPhaseRequirements(artifacts, phase) {
  const errors = [];
  const warnings = [];
  if (phase === 'research' && !artifacts.brief) {
    errors.push({ code: 'PROJECT_NO_BRIEF', message: 'research phase requires brief.md' });
  }
  if (phase === 'plan' && !artifacts.brief) {
    errors.push({ code: 'PROJECT_NO_BRIEF', message: 'plan phase requires brief.md' });
  }
  if (phase === 'execute' && !artifacts.plan) {
    errors.push({ code: 'PROJECT_NO_PLAN', message: 'execute phase requires plan.md' });
  }
  if (phase === 'review') {
    if (!artifacts.brief) {
      errors.push({ code: 'PROJECT_NO_BRIEF', message: 'review phase requires brief.md' });
    }
    if (!artifacts.progress) {
      warnings.push({
        code: 'PROJECT_NO_PROGRESS',
        message: 'review phase: progress.json absent — scope detection will fall back to brief.md mtime',
      });
    }
  }
  return { valid: errors.length === 0, errors, warnings, parsed: artifacts };
}
