import { readFileSync, existsSync } from 'fs';

/**
 * Content Validator - Validates structure and content of output files
 *
 * Ensures spec.md, tasks.json, and other outputs have required sections
 * and proper structure before allowing phase transitions.
 */

/**
 * Validate spec.md structure
 * @param {string} specPath - Path to spec.md file
 * @returns {Object} Validation result
 */
export function validateSpecContent(specPath) {
  if (!existsSync(specPath)) {
    return {
      valid: false,
      missing: ['File does not exist'],
      errors: ['Spec file not found at: ' + specPath]
    };
  }

  const content = readFileSync(specPath, 'utf8');

  // Required sections for a complete spec
  const requiredSections = [
    '## Overview',
    '## Requirements',
    '## Technical Design',
    '## Data Model',
    '## API Contracts'
  ];

  const missing = requiredSections.filter(section => !content.includes(section));

  // Additional quality checks
  const errors = [];
  const warnings = [];

  // Check minimum content length
  if (content.length < 500) {
    warnings.push('Spec seems very short (< 500 characters). Consider adding more detail.');
  }

  // Check for placeholder text that should be replaced
  const placeholders = ['TODO', 'TBD', 'PLACEHOLDER', '{{'];
  placeholders.forEach(placeholder => {
    if (content.includes(placeholder)) {
      warnings.push(`Spec contains "${placeholder}" - ensure all placeholders are replaced`);
    }
  });

  // Check for anti-patterns mentioned in the plan
  if (content.toLowerCase().includes('manual azure portal')) {
    errors.push(
      'Spec mentions manual Azure portal creation. ' +
      'All infrastructure must be defined in Bicep (Infrastructure as Code).'
    );
  }

  if (content.toLowerCase().includes('create resource manually')) {
    errors.push(
      'Spec mentions manual resource creation. ' +
      'Use IaC (Bicep) for all infrastructure resources.'
    );
  }

  return {
    valid: missing.length === 0 && errors.length === 0,
    missing,
    errors,
    warnings,
    sections: {
      required: requiredSections.length,
      found: requiredSections.length - missing.length
    }
  };
}

/**
 * Validate tasks.json structure
 * @param {string} tasksPath - Path to tasks.json file
 * @returns {Object} Validation result
 */
export function validateTasksContent(tasksPath) {
  if (!existsSync(tasksPath)) {
    return {
      valid: false,
      errors: ['Tasks file not found at: ' + tasksPath]
    };
  }

  let tasks;
  try {
    const content = readFileSync(tasksPath, 'utf8');
    tasks = JSON.parse(content);
  } catch (error) {
    return {
      valid: false,
      errors: ['Invalid JSON in tasks file: ' + error.message]
    };
  }

  const errors = [];
  const warnings = [];

  // Check required top-level fields
  if (!tasks.feature) {
    errors.push('Missing "feature" field in tasks.json');
  }

  if (!tasks.tasks || !Array.isArray(tasks.tasks)) {
    errors.push('Missing or invalid "tasks" array in tasks.json');
    return { valid: false, errors, warnings };
  }

  if (tasks.tasks.length === 0) {
    errors.push('Tasks array is empty - no tasks defined');
    return { valid: false, errors, warnings };
  }

  // Validate individual tasks
  tasks.tasks.forEach((task, index) => {
    const taskId = task.id || `Task ${index}`;

    // Check required fields
    if (!task.id) {
      errors.push(`${taskId}: Missing "id" field`);
    } else if (!/^(T\d{3}|CHECKPOINT_\d{3})$/.test(task.id)) {
      warnings.push(`${taskId}: ID should follow format T### or CHECKPOINT_###`);
    }

    if (!task.title) {
      errors.push(`${taskId}: Missing "title" field`);
    }

    if (!task.description) {
      errors.push(`${taskId}: Missing "description" field`);
    }

    if (!task.dependencies) {
      errors.push(`${taskId}: Missing "dependencies" field (use empty array if no deps)`);
    }

    // For regular tasks (not checkpoints)
    if (task.id && task.id.startsWith('T')) {
      if (!task.category) {
        warnings.push(`${taskId}: Missing "category" field`);
      }

      if (!task.estimatedMinutes) {
        warnings.push(`${taskId}: Missing "estimatedMinutes" field`);
      }

      if (!task.files || task.files.length === 0) {
        warnings.push(`${taskId}: No files specified - consider adding affected files`);
      }
    }

    // For checkpoints
    if (task.id && task.id.startsWith('CHECKPOINT')) {
      if (!task.afterTasks || task.afterTasks.length === 0) {
        warnings.push(`${taskId}: Checkpoint should specify "afterTasks"`);
      }

      if (!task.validations || task.validations.length === 0) {
        warnings.push(`${taskId}: Checkpoint should specify "validations"`);
      }
    }
  });

  // Check for orphaned tasks (missing dependencies)
  const taskIds = new Set(tasks.tasks.map(t => t.id));
  tasks.tasks.forEach(task => {
    if (task.dependencies && Array.isArray(task.dependencies)) {
      task.dependencies.forEach(depId => {
        if (depId && !taskIds.has(depId)) {
          errors.push(`${task.id}: References non-existent dependency "${depId}"`);
        }
      });
    }
  });

  // Check for circular dependencies (simple check)
  const hasCycle = (taskId, visited = new Set()) => {
    if (visited.has(taskId)) return true;
    visited.add(taskId);

    const task = tasks.tasks.find(t => t.id === taskId);
    if (!task || !task.dependencies) return false;

    return task.dependencies.some(depId => hasCycle(depId, new Set(visited)));
  };

  tasks.tasks.forEach(task => {
    if (task.id && hasCycle(task.id)) {
      errors.push(`Circular dependency detected involving task ${task.id}`);
    }
  });

  return {
    valid: errors.length === 0,
    errors,
    warnings,
    stats: {
      totalTasks: tasks.tasks.length,
      regularTasks: tasks.tasks.filter(t => t.id?.startsWith('T')).length,
      checkpoints: tasks.tasks.filter(t => t.id?.startsWith('CHECKPOINT')).length
    }
  };
}

/**
 * Validate contracts file structure (C# contracts)
 * @param {string} contractsPath - Path to contracts file
 * @returns {Object} Validation result
 */
export function validateContractsContent(contractsPath) {
  if (!existsSync(contractsPath)) {
    return {
      valid: false,
      errors: ['Contracts file not found at: ' + contractsPath]
    };
  }

  const content = readFileSync(contractsPath, 'utf8');
  const errors = [];
  const warnings = [];

  // Check for basic C# structure
  if (!content.includes('namespace')) {
    errors.push('Contracts file missing namespace declaration');
  }

  // Check for at least one interface or record
  const hasInterface = /interface\s+\w+/.test(content);
  const hasRecord = /record\s+\w+/.test(content);
  const hasClass = /class\s+\w+/.test(content);

  if (!hasInterface && !hasRecord && !hasClass) {
    errors.push('Contracts file should define at least one interface, record, or class');
  }

  // Check for common anti-patterns
  if (content.includes('// TODO') || content.includes('// PLACEHOLDER')) {
    warnings.push('Contracts contain TODO/PLACEHOLDER comments - ensure they are completed');
  }

  return {
    valid: errors.length === 0,
    errors,
    warnings,
    found: {
      hasNamespace: content.includes('namespace'),
      hasInterfaces: hasInterface,
      hasRecords: hasRecord,
      hasClasses: hasClass
    }
  };
}

/**
 * Validate proposal.md structure
 * @param {string} proposalPath - Path to proposal.md file
 * @returns {Object} Validation result
 */
export function validateProposalContent(proposalPath) {
  if (!existsSync(proposalPath)) {
    return {
      valid: false,
      errors: ['Proposal file not found at: ' + proposalPath]
    };
  }

  const content = readFileSync(proposalPath, 'utf8');
  const errors = [];
  const warnings = [];

  // Required sections
  const requiredSections = [
    '## Problem Statement',
    '## Proposed Solution'
  ];

  const missing = requiredSections.filter(section => !content.includes(section));
  missing.forEach(section => errors.push(`Missing required section: ${section}`));

  // Check for minimum content
  if (content.length < 300) {
    warnings.push('Proposal seems very brief (< 300 characters)');
  }

  return {
    valid: errors.length === 0,
    errors,
    warnings,
    sections: {
      required: requiredSections.length,
      found: requiredSections.length - missing.length
    }
  };
}

/**
 * Validate all outputs for a feature comprehensively
 * @param {Object} featureState - Feature state object
 * @param {string} targetPhase - Target phase for validation
 * @returns {Object} Comprehensive validation result
 */
export function validateFeatureOutputs(featureState, targetPhase) {
  const results = {
    valid: true,
    validations: []
  };

  // Validate based on target phase
  if (targetPhase === 'clarify' || targetPhase === 'tasks' || targetPhase === 'implement') {
    // Spec is required
    if (featureState.outputs?.spec?.created) {
      const specResult = validateSpecContent(featureState.outputs.spec.path);
      results.validations.push({ type: 'spec', ...specResult });
      if (!specResult.valid) results.valid = false;
    } else {
      results.valid = false;
      results.validations.push({
        type: 'spec',
        valid: false,
        errors: ['Spec file not created']
      });
    }
  }

  if (targetPhase === 'implement') {
    // Tasks are required
    if (featureState.outputs?.tasks?.created) {
      const tasksResult = validateTasksContent(featureState.outputs.tasks.path);
      results.validations.push({ type: 'tasks', ...tasksResult });
      if (!tasksResult.valid) results.valid = false;
    } else {
      results.valid = false;
      results.validations.push({
        type: 'tasks',
        valid: false,
        errors: ['Tasks file not created']
      });
    }
  }

  return results;
}
