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

export interface SystemPromptContext {
  tenantId: string;
  serverContext?: string;
  skills?: string[];
  riskBoundary?: string;
  additionalInstructions?: string;
}

/**
 * Builds system prompts for Claude CLI sessions.
 * Generates and optionally saves system prompt files that provide
 * context about the tenant, server environment, and operational boundaries.
 */
@Injectable()
export class SystemPromptBuilder {
  private readonly logger = new Logger(SystemPromptBuilder.name);

  constructor(private readonly configService: ConfigService) {}

  /**
   * Builds a system prompt string from the given context.
   */
  build(context: SystemPromptContext): string {
    const parts: string[] = [];

    // Base instruction
    parts.push(
      'You are iAgent, an AI-powered server cluster operations assistant built on IT0. ' +
        'You help users manage server infrastructure, deploy AI agents, and automate operations safely and efficiently.\n\n' +
        '## OpenClaw Agent Deployment\n' +
        'You can deploy real OpenClaw AI agent instances for users. OpenClaw is an open-source autonomous AI agent.\n' +
        'To deploy an OpenClaw instance, call the IT0 API:\n' +
        '  POST /api/v1/agent/instances\n' +
        '  Body: { "name": "<user-given name>", "userId": "<user id>", "usePool": true }\n' +
        'The instance will be deployed on a pool server automatically. After creation, the user can connect\n' +
        'their OpenClaw to Telegram, WhatsApp, or other channels via the channel configuration.\n' +
        'To list existing instances: GET /api/v1/agent/instances\n' +
        'To stop an instance:       PUT /api/v1/agent/instances/:id/stop\n' +
        'To remove an instance:     DELETE /api/v1/agent/instances/:id\n\n' +
        'When a user says they want to create an OpenClaw, a personal AI agent, or an autonomous agent,\n' +
        'confirm their desired name, then call the deployment API and report the result.',
    );

    // Tenant context
    parts.push(`\nTenant: ${context.tenantId}`);

    // Server context (available servers, environment, etc.)
    if (context.serverContext) {
      parts.push(`\nServer Environment:\n${context.serverContext}`);
    }

    // Available skills
    if (context.skills && context.skills.length > 0) {
      parts.push(
        `\nAvailable Skills: ${context.skills.join(', ')}`,
      );
    }

    // Risk boundary
    if (context.riskBoundary) {
      parts.push(`\nRisk Boundary:\n${context.riskBoundary}`);
    } else {
      parts.push(
        '\nRisk Boundary:\n' +
          '- L0 (Read-only): Auto-execute (ls, cat, df, top, etc.)\n' +
          '- L1 (Low-risk write): Confirm before execution\n' +
          '- L2 (High-risk): Require multi-channel approval\n' +
          '- L3 (Forbidden): Block entirely (rm -rf /, mkfs, etc.)',
      );
    }

    // Additional instructions
    if (context.additionalInstructions) {
      parts.push(`\n${context.additionalInstructions}`);
    }

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

  /**
   * Builds the system prompt and saves it to a temporary file.
   * Returns the file path. Useful for the CLI --system-prompt flag
   * when using file-based prompts.
   */
  async buildAndSave(
    context: SystemPromptContext,
    sessionId: string,
  ): Promise<string> {
    const prompt = this.build(context);
    const tmpDir = this.configService.get<string>(
      'SYSTEM_PROMPT_DIR',
      path.join(process.cwd(), '.tmp', 'prompts'),
    );

    if (!fs.existsSync(tmpDir)) {
      fs.mkdirSync(tmpDir, { recursive: true });
    }

    const filePath = path.join(tmpDir, `${sessionId}.md`);
    fs.writeFileSync(filePath, prompt, 'utf-8');

    this.logger.debug(`System prompt saved to ${filePath}`);
    return filePath;
  }

  /**
   * Cleans up a saved system prompt file for a session.
   */
  cleanup(sessionId: string): void {
    const tmpDir = this.configService.get<string>(
      'SYSTEM_PROMPT_DIR',
      path.join(process.cwd(), '.tmp', 'prompts'),
    );
    const filePath = path.join(tmpDir, `${sessionId}.md`);

    if (fs.existsSync(filePath)) {
      fs.unlinkSync(filePath);
      this.logger.debug(`Cleaned up system prompt: ${filePath}`);
    }
  }
}
