/**
 * Artifact Trail — Debugging trail system
 *
 * Creates checkpoint artifact directories and saves:
 * - Intermediate files (spec drafts, contract drafts)
 * - Agent reasoning logs
 * - Validator output logs
 * - Failure artifacts on checkpoint failure
 *
 * Structure:
 *   .morph/features/{feature}/artifacts/
 *     checkpoint-{n}/
 *       spec-draft.md
 *       contracts-draft.cs
 *       agent-reasoning.json
 *       validator-output.json
 *     checkpoint-{n}/failures/
 *       failure-detail.json
 */

import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'fs';
import { join } from 'path';

const BASE_DIR = join(process.cwd(), '.morph/features');

// ============================================================================
// Path Helpers
// ============================================================================

function artifactsDir(feature) {
  return join(BASE_DIR, feature, 'artifacts');
}

function checkpointDir(feature, checkpointNum) {
  return join(artifactsDir(feature), `checkpoint-${checkpointNum}`);
}

function failuresDir(feature, checkpointNum) {
  return join(checkpointDir(feature, checkpointNum), 'failures');
}

function ensureDir(dir) {
  if (!existsSync(dir)) {
    mkdirSync(dir, { recursive: true });
  }
  return dir;
}

// ============================================================================
// Checkpoint Artifacts
// ============================================================================

/**
 * Initialize a checkpoint artifact directory
 * @param {string} feature - Feature name
 * @param {number} checkpointNum - Checkpoint number
 * @returns {string} Path to checkpoint directory
 */
export function initCheckpointArtifacts(feature, checkpointNum) {
  const dir = checkpointDir(feature, checkpointNum);
  ensureDir(dir);

  const manifest = {
    feature,
    checkpointNum,
    createdAt: new Date().toISOString(),
    files: []
  };

  writeFileSync(join(dir, 'manifest.json'), JSON.stringify(manifest, null, 2), 'utf8');
  return dir;
}

/**
 * Save an intermediate artifact file to a checkpoint directory
 * @param {string} feature - Feature name
 * @param {number} checkpointNum - Checkpoint number
 * @param {string} filename - File name (e.g., 'spec-draft.md')
 * @param {string} content - File content
 * @returns {string} Full path to saved file
 */
export function saveArtifact(feature, checkpointNum, filename, content) {
  const dir = ensureDir(checkpointDir(feature, checkpointNum));
  const filePath = join(dir, filename);

  writeFileSync(filePath, content, 'utf8');

  // Update manifest
  const manifestPath = join(dir, 'manifest.json');
  if (existsSync(manifestPath)) {
    const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
    if (!manifest.files.includes(filename)) {
      manifest.files.push(filename);
      manifest.updatedAt = new Date().toISOString();
      writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
    }
  }

  return filePath;
}

/**
 * Save agent reasoning log
 * @param {string} feature - Feature name
 * @param {number} checkpointNum - Checkpoint number
 * @param {Object} reasoning - Agent reasoning data
 */
export function saveAgentReasoning(feature, checkpointNum, reasoning) {
  const entry = {
    timestamp: new Date().toISOString(),
    ...reasoning
  };
  saveArtifact(feature, checkpointNum, 'agent-reasoning.json', JSON.stringify(entry, null, 2));
}

/**
 * Save validator output log
 * @param {string} feature - Feature name
 * @param {number} checkpointNum - Checkpoint number
 * @param {Object} validatorOutput - Validator results
 */
export function saveValidatorOutput(feature, checkpointNum, validatorOutput) {
  const entry = {
    timestamp: new Date().toISOString(),
    ...validatorOutput
  };
  saveArtifact(feature, checkpointNum, 'validator-output.json', JSON.stringify(entry, null, 2));
}

// ============================================================================
// Failure Artifacts
// ============================================================================

/**
 * Save failure artifacts when a checkpoint fails
 * @param {string} feature - Feature name
 * @param {number} checkpointNum - Checkpoint number
 * @param {Object} failure - Failure details
 * @param {string} failure.reason - Failure reason
 * @param {Array} failure.errors - Array of error objects
 * @param {number} failure.attemptNumber - Which retry attempt (1-3)
 */
export function saveFailureArtifacts(feature, checkpointNum, failure) {
  const dir = ensureDir(failuresDir(feature, checkpointNum));
  const filename = `failure-attempt-${failure.attemptNumber || 1}.json`;

  const entry = {
    feature,
    checkpointNum,
    timestamp: new Date().toISOString(),
    ...failure
  };

  writeFileSync(join(dir, filename), JSON.stringify(entry, null, 2), 'utf8');
  return join(dir, filename);
}

/**
 * Get all failure artifacts for a checkpoint
 * @param {string} feature - Feature name
 * @param {number} checkpointNum - Checkpoint number
 * @returns {Array} Array of failure records
 */
export function getFailureArtifacts(feature, checkpointNum) {
  const dir = failuresDir(feature, checkpointNum);
  if (!existsSync(dir)) return [];

  const files = readdirSync(dir).filter(f => f.endsWith('.json'));

  return files.map(f => {
    try {
      return JSON.parse(readFileSync(join(dir, f), 'utf8'));
    } catch {
      return null;
    }
  }).filter(Boolean);
}

/**
 * List all checkpoints for a feature
 * @param {string} feature - Feature name
 * @returns {Array} Array of checkpoint info objects
 */
export function listCheckpointArtifacts(feature) {
  const dir = artifactsDir(feature);
  if (!existsSync(dir)) return [];

  try {
    return readdirSync(dir, { withFileTypes: true })
      .filter(d => d.isDirectory() && d.name.startsWith('checkpoint-'))
      .map(d => {
        const checkpointPath = join(dir, d.name);
        const manifestPath = join(checkpointPath, 'manifest.json');
        if (existsSync(manifestPath)) {
          return JSON.parse(readFileSync(manifestPath, 'utf8'));
        }
        return { name: d.name, path: checkpointPath };
      });
  } catch {
    return [];
  }
}
