import { Injectable, Logger } from "@nestjs/common";
import { AgentLifecycleService } from "../spawner/agent-lifecycle.service";
import { ValkeyService } from "../valkey/valkey.service";
import { CleanupService } from "./cleanup.service";
import type { AgentState } from "../valkey/types";

/**
 * Result of killing all agents operation
 */
export interface KillAllResult {
  /** Total number of agents processed */
  total: number;
  /** Number of agents successfully killed */
  killed: number;
  /** Number of agents that failed to kill */
  failed: number;
  /** Error messages for failed kills */
  errors?: string[];
}

/**
 * Service for emergency stop (killswitch) functionality
 *
 * Provides immediate termination of agents with cleanup:
 * - Updates agent state to 'killed'
 * - Delegates cleanup to CleanupService
 * - Logs audit trail
 *
 * Killswitch bypasses all queues and must respond within seconds.
 */
@Injectable()
export class KillswitchService {
  private readonly logger = new Logger(KillswitchService.name);

  constructor(
    private readonly lifecycleService: AgentLifecycleService,
    private readonly valkeyService: ValkeyService,
    private readonly cleanupService: CleanupService
  ) {
    this.logger.log("KillswitchService initialized");
  }

  /**
   * Kill a single agent immediately with full cleanup
   *
   * @param agentId Unique agent identifier
   * @throws Error if agent not found or state transition fails
   */
  async killAgent(agentId: string): Promise<void> {
    this.logger.warn(`KILLSWITCH ACTIVATED for agent: ${agentId}`);

    // Get agent state
    const agentState = await this.valkeyService.getAgentState(agentId);

    if (!agentState) {
      const error = `Agent ${agentId} not found`;
      this.logger.error(error);
      throw new Error(error);
    }

    // Log audit trail
    this.logAudit("KILL_AGENT", agentId, agentState);

    // Transition to killed state first (this validates the state transition)
    // If this fails (e.g., already killed), we should not perform cleanup
    await this.lifecycleService.transitionToKilled(agentId);

    // Delegate cleanup to CleanupService after successful state transition
    const cleanupResult = await this.cleanupService.cleanup(agentState);

    // Log cleanup results in audit trail
    const cleanupSummary = {
      docker: cleanupResult.docker.success
        ? "success"
        : `failed: ${cleanupResult.docker.error ?? "unknown"}`,
      worktree: cleanupResult.worktree.success
        ? "success"
        : `failed: ${cleanupResult.worktree.error ?? "unknown"}`,
      state: cleanupResult.state.success
        ? "success"
        : `failed: ${cleanupResult.state.error ?? "unknown"}`,
    };

    this.logger.warn(
      `Agent ${agentId} killed successfully. Cleanup: ${JSON.stringify(cleanupSummary)}`
    );
  }

  /**
   * Kill all active agents (spawning or running)
   *
   * @returns Summary of kill operation
   */
  async killAllAgents(): Promise<KillAllResult> {
    this.logger.warn("KILLSWITCH ACTIVATED for ALL AGENTS");

    // Get all agents
    const allAgents = await this.valkeyService.listAgents();

    // Filter to only active agents (spawning or running)
    const activeAgents = allAgents.filter(
      (agent) => agent.status === "spawning" || agent.status === "running"
    );

    if (activeAgents.length === 0) {
      this.logger.log("No active agents to kill");
      return { total: 0, killed: 0, failed: 0 };
    }

    this.logger.warn(`Killing ${activeAgents.length.toString()} active agents`);

    // Log audit trail
    this.logAudit(
      "KILL_ALL_AGENTS",
      "all",
      undefined,
      `Total active agents: ${activeAgents.length.toString()}`
    );

    // Kill each agent (continue on failures)
    let killed = 0;
    let failed = 0;
    const errors: string[] = [];

    for (const agent of activeAgents) {
      try {
        await this.killAgent(agent.agentId);
        killed++;
      } catch (error) {
        failed++;
        const errorMsg = `Failed to kill agent ${agent.agentId}: ${
          error instanceof Error ? error.message : String(error)
        }`;
        this.logger.error(errorMsg);
        errors.push(errorMsg);
      }
    }

    const result: KillAllResult = {
      total: activeAgents.length,
      killed,
      failed,
      errors: errors.length > 0 ? errors : undefined,
    };

    this.logger.warn(
      `Kill all completed: ${killed.toString()} killed, ${failed.toString()} failed out of ${activeAgents.length.toString()}`
    );

    return result;
  }

  /**
   * Log audit trail for killswitch operations
   */
  private logAudit(
    operation: "KILL_AGENT" | "KILL_ALL_AGENTS",
    agentId: string,
    agentState?: AgentState,
    additionalInfo?: string
  ): void {
    const auditLog = {
      timestamp: new Date().toISOString(),
      operation,
      agentId,
      agentStatus: agentState?.status,
      taskId: agentState?.taskId,
      additionalInfo,
    };

    this.logger.warn(`[AUDIT] Killswitch: ${JSON.stringify(auditLog)}`);
  }
}
