import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as fs from 'fs';
import * as path from 'path';

export interface HookConfig {
  hooks?: {
    PreToolUse?: Array<{
      matcher: string;
      hook: { type: string; command?: string; url?: string };
    }>;
    PostToolUse?: Array<{
      matcher: string;
      hook: { type: string; command?: string; url?: string };
    }>;
    Notification?: Array<{
      matcher: string;
      hook: { type: string; command?: string; url?: string };
    }>;
  };
}

export interface ClaudeSettings {
  permissions?: {
    allow?: string[];
    deny?: string[];
  };
  hooks?: HookConfig['hooks'];
}

/**
 * Manages .claude/settings.json hook configurations for Claude CLI sessions.
 * Handles reading, writing, and merging hook configurations that control
 * how the CLI interacts with tool use events.
 */
@Injectable()
export class HookConfigManager {
  private readonly logger = new Logger(HookConfigManager.name);

  constructor(private readonly configService: ConfigService) {}

  /**
   * Reads the current .claude/settings.json from the given working directory.
   */
  readSettings(workingDir: string): ClaudeSettings {
    const settingsPath = path.join(workingDir, '.claude', 'settings.json');

    if (!fs.existsSync(settingsPath)) {
      return {};
    }

    try {
      const content = fs.readFileSync(settingsPath, 'utf-8');
      return JSON.parse(content) as ClaudeSettings;
    } catch (err: any) {
      this.logger.warn(
        `Failed to read .claude/settings.json: ${err.message}`,
      );
      return {};
    }
  }

  /**
   * Writes the given settings to .claude/settings.json in the working directory.
   */
  writeSettings(workingDir: string, settings: ClaudeSettings): void {
    const claudeDir = path.join(workingDir, '.claude');
    if (!fs.existsSync(claudeDir)) {
      fs.mkdirSync(claudeDir, { recursive: true });
    }

    const settingsPath = path.join(claudeDir, 'settings.json');
    fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
    this.logger.debug(`Wrote settings to ${settingsPath}`);
  }

  /**
   * Merges hook configurations into the existing settings.
   * Adds new hooks without removing existing ones.
   */
  mergeHooks(workingDir: string, hooks: HookConfig['hooks']): void {
    const settings = this.readSettings(workingDir);

    if (!settings.hooks) {
      settings.hooks = {};
    }

    if (hooks?.PreToolUse) {
      settings.hooks.PreToolUse = [
        ...(settings.hooks.PreToolUse || []),
        ...hooks.PreToolUse,
      ];
    }

    if (hooks?.PostToolUse) {
      settings.hooks.PostToolUse = [
        ...(settings.hooks.PostToolUse || []),
        ...hooks.PostToolUse,
      ];
    }

    if (hooks?.Notification) {
      settings.hooks.Notification = [
        ...(settings.hooks.Notification || []),
        ...hooks.Notification,
      ];
    }

    this.writeSettings(workingDir, settings);
  }

  /**
   * Sets tool permissions (allow/deny lists).
   */
  setPermissions(
    workingDir: string,
    allow: string[],
    deny: string[],
  ): void {
    const settings = this.readSettings(workingDir);
    settings.permissions = { allow, deny };
    this.writeSettings(workingDir, settings);
  }

  /**
   * Generates a default hook configuration for IT0 command guard integration.
   * Adds a PreToolUse hook that calls back to the agent-service for
   * command risk classification before allowing Bash tool execution.
   */
  generateCommandGuardHooks(callbackUrl: string): HookConfig['hooks'] {
    return {
      PreToolUse: [
        {
          matcher: 'Bash',
          hook: {
            type: 'url',
            url: `${callbackUrl}/api/v1/agent/hooks/pre-tool-use`,
          },
        },
      ],
      PostToolUse: [
        {
          matcher: 'Bash',
          hook: {
            type: 'url',
            url: `${callbackUrl}/api/v1/agent/hooks/post-tool-use`,
          },
        },
      ],
    };
  }
}
