/**
 * Hooks system for tool execution.
 *
 * Hooks allow external code to intercept tool execution at two points:
 *   - PreToolUse:  Before a tool executes. Can block or modify input.
 *   - PostToolUse: After a tool executes. Can observe/log results.
 *
 * Hook registration:
 *   registerHook('PreToolUse', hookFn)
 *   registerHook('PostToolUse', hookFn)
 *
 * Hook functions:
 *   PreToolUse:  async (toolName, input, context) => { allowed, reason?, modifiedInput? }
 *   PostToolUse: async (toolName, input, output, context) => void
 *
 * Config-based hooks can also be loaded from a hooks config object:
 *   { preToolUse: [{ tool: 'Bash', match: 'rm', action: 'block', reason: '...' }] }
 */

const _hooks = {
  PreToolUse: [],
  PostToolUse: []
};

/**
 * Register a hook function.
 * @param {'PreToolUse'|'PostToolUse'} phase
 * @param {Function} fn
 * @returns {Function} Unregister function
 */
export function registerHook(phase, fn) {
  if (!_hooks[phase]) {
    throw new Error(`Unknown hook phase: "${phase}". Use "PreToolUse" or "PostToolUse".`);
  }
  if (typeof fn !== 'function') {
    throw new Error('Hook must be a function');
  }
  _hooks[phase].push(fn);

  // Return unregister function
  return () => {
    const idx = _hooks[phase].indexOf(fn);
    if (idx >= 0) _hooks[phase].splice(idx, 1);
  };
}

/**
 * Clear all hooks (useful for testing).
 */
export function clearHooks() {
  _hooks.PreToolUse.length = 0;
  _hooks.PostToolUse.length = 0;
}

/**
 * Run all PreToolUse hooks in order.
 * If any hook returns { allowed: false }, execution is blocked.
 * If a hook returns { modifiedInput }, the input is updated.
 *
 * @param {string} toolName
 * @param {Object} input
 * @param {Object} context
 * @returns {Promise<{ allowed: boolean, reason?: string, modifiedInput?: Object }>}
 */
export async function runPreToolUse(toolName, input, context) {
  for (const hook of _hooks.PreToolUse) {
    try {
      const result = await hook(toolName, input, context);
      if (result && result.allowed === false) {
        return { allowed: false, reason: result.reason || 'Blocked by hook' };
      }
      if (result && result.modifiedInput) {
        return { allowed: true, modifiedInput: result.modifiedInput };
      }
    } catch (err) {
      console.error(`[hooks] PreToolUse hook error: ${err.message}`);
      // Hook errors don't block execution
    }
  }
  return { allowed: true };
}

/**
 * Run all PostToolUse hooks.
 * PostToolUse hooks are fire-and-forget — errors are logged but ignored.
 *
 * @param {string} toolName
 * @param {Object} input
 * @param {Object} output
 * @param {Object} context
 */
export async function runPostToolUse(toolName, input, output, context) {
  for (const hook of _hooks.PostToolUse) {
    try {
      await hook(toolName, input, output, context);
    } catch (err) {
      console.error(`[hooks] PostToolUse hook error: ${err.message}`);
    }
  }
}

/**
 * Load hooks from a configuration object.
 * Config format:
 *   {
 *     preToolUse: [
 *       { tool: 'Bash', match: 'rm -rf', action: 'block', reason: 'Dangerous command' },
 *       { tool: '*', action: 'log' }
 *     ],
 *     postToolUse: [
 *       { tool: '*', action: 'log' }
 *     ]
 *   }
 *
 * @param {Object} config Hooks configuration
 * @returns {Function[]} Array of unregister functions
 */
export function loadHooksFromConfig(config) {
  const unregisters = [];

  if (config?.preToolUse) {
    for (const rule of config.preToolUse) {
      const unreg = registerHook('PreToolUse', (toolName, input, context) => {
        // Check tool name match
        if (rule.tool !== '*' && rule.tool !== toolName) {
          return { allowed: true };
        }

        // Check pattern match against serialized input
        if (rule.match) {
          const inputStr = JSON.stringify(input);
          if (!inputStr.includes(rule.match)) {
            return { allowed: true };
          }
        }

        if (rule.action === 'block') {
          return { allowed: false, reason: rule.reason || `Blocked by config rule for ${toolName}` };
        }

        if (rule.action === 'log') {
          console.log(`[hook] PreToolUse ${toolName}: ${JSON.stringify(input).slice(0, 200)}`);
        }

        return { allowed: true };
      });
      unregisters.push(unreg);
    }
  }

  if (config?.postToolUse) {
    for (const rule of config.postToolUse) {
      const unreg = registerHook('PostToolUse', (toolName, input, output, context) => {
        if (rule.tool !== '*' && rule.tool !== toolName) return;

        if (rule.action === 'log') {
          const status = output?.is_error ? 'ERROR' : 'OK';
          console.log(`[hook] PostToolUse ${toolName} [${status}]: ${(output?.content || '').slice(0, 200)}`);
        }
      });
      unregisters.push(unreg);
    }
  }

  return unregisters;
}

/**
 * Get current hook counts (for diagnostics).
 */
export function getHookCounts() {
  return {
    PreToolUse: _hooks.PreToolUse.length,
    PostToolUse: _hooks.PostToolUse.length
  };
}
