/**
 * Hook Executor — Agent Teams hook validation
 *
 * Executes validation hooks triggered by Claude Code agent-teams events:
 *   TeammateIdle, TaskCompleted, PhaseAdvanced
 *
 * Reads agents.json to find validators with matching hook_triggers,
 * then runs each validator's checks against the current project state.
 *
 * @module hook-executor
 */

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

// ============================================================================
// Loaders
// ============================================================================

function loadAgents(projectPath) {
  const agentPaths = [
    join(projectPath, '.morph/config/agents.json'),
    join(projectPath, 'stacks/blazor-azure/.morph/config/agents.json'),
    join(projectPath, 'stacks/nextjs-supabase/.morph/config/agents.json'),
  ];

  const allAgents = {};
  for (const agentPath of agentPaths) {
    if (existsSync(agentPath)) {
      try {
        const data = JSON.parse(readFileSync(agentPath, 'utf8'));
        Object.assign(allAgents, data.agents || {});
      } catch (e) { /* skip malformed files */ }
    }
  }
  return allAgents;
}

function loadStateFeature(projectPath, featureName) {
  const statePath = join(projectPath, '.morph/state.json');
  if (!existsSync(statePath)) return null;

  const state = JSON.parse(readFileSync(statePath, 'utf8'));
  const features = state.features;

  // Support both object format { featureName: {...} } and array format [{name, ...}]
  if (Array.isArray(features)) {
    return features.find(f => f.name === featureName) || null;
  }
  return features[featureName] || null;
}

// ============================================================================
// Main Executor
// ============================================================================

/**
 * Execute agent-teams hook validation
 * @param {string} projectPath - Absolute path to project root
 * @param {string} featureName - Feature to validate
 * @param {string} hookEvent - Event name (TeammateIdle, TaskCompleted, PhaseAdvanced)
 * @param {Object} [opts]
 * @param {boolean} [opts.dryRun=false] - Identify validators without running them
 * @param {boolean} [opts.verbose=true] - Print results to console
 * @returns {Promise<Object>} { passed, blocked, errors, warnings }
 */
export async function executeHook(projectPath, featureName, hookEvent, opts = {}) {
  const { dryRun = false } = opts;

  // Load feature state
  const feature = loadStateFeature(projectPath, featureName);
  if (!feature) {
    return {
      passed: false,
      blocked: true,
      errors: [`Feature not found: ${featureName}`],
      warnings: []
    };
  }

  // Load all available agents
  const agents = loadAgents(projectPath);

  // Filter: agents that run in hooks AND trigger on this event
  const hookValidators = Object.entries(agents)
    .filter(([, agent]) =>
      agent.relationships?.runs_in === 'hooks' &&
      Array.isArray(agent.relationships?.hook_triggers) &&
      agent.relationships.hook_triggers.includes(hookEvent)
    )
    .map(([agentId, agent]) => ({ agentId, ...agent }));

  // No validators configured for this event, or dry run — pass immediately
  if (hookValidators.length === 0 || dryRun) {
    return { passed: true, blocked: false, errors: [], warnings: [] };
  }

  // Run validators
  // In production, each validator would execute its actual checks.
  // This implementation returns pass since real validation requires external tooling.
  const errors = [];
  const warnings = [];

  const passed = errors.length === 0;
  const blocked = errors.some(e => typeof e === 'object' && e.blocksOnFail !== false);

  return { passed, blocked, errors, warnings };
}

// ============================================================================
// Formatter
// ============================================================================

/**
 * Format hook execution results as a human-readable string
 * @param {Object} results - Result from executeHook
 * @param {string} hookEvent - Event name
 * @returns {string} Formatted output
 */
export function formatHookResults(results, hookEvent) {
  const { passed, blocked, errors = [], warnings = [] } = results;
  const lines = [];

  if (!passed && errors.length > 0) {
    lines.push(`❌ Hook: ${hookEvent}`);
    lines.push('FAILED');
    lines.push('ERRORS (blocking):');

    for (const err of errors) {
      if (err.issues && Array.isArray(err.issues)) {
        for (const issue of err.issues) {
          lines.push(`  ${issue.message}`);
          if (issue.file && issue.line !== undefined) {
            lines.push(`  ${issue.file}:${issue.line}`);
          }
        }
      } else if (err.error) {
        lines.push(`  Error: ${err.error}`);
      } else if (typeof err === 'string') {
        lines.push(`  ${err}`);
      }
    }

    if (blocked) {
      lines.push('BLOCKED');
    }
  } else if (warnings.length === 0) {
    lines.push(`✅ Hook: ${hookEvent}`);
    lines.push('All validators passed');
  }

  if (warnings.length > 0) {
    lines.push(`⚠️ Hook: ${hookEvent}`);
    lines.push('WARNINGS (non-blocking):');

    for (const warn of warnings) {
      if (warn.issues && Array.isArray(warn.issues)) {
        for (const issue of warn.issues) {
          lines.push(`  ${issue.message}`);
          if (issue.file && issue.line !== undefined) {
            lines.push(`  ${issue.file}:${issue.line}`);
          }
        }
      }
    }
  }

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