/**
 * File Conflict Detection
 *
 * Tracks which files each session modifies and detects when multiple
 * active sessions touch the same files simultaneously.
 * In-memory only — no persistence needed.
 */

import { createLogger } from "./logger.js";
import type { Session } from "./ws-bridge-types.js";
import type { BrowserIncomingMessage, ContentBlock } from "./session-types.js";
import { getName as getSessionName } from "./session-names.js";

const log = createLogger("ws-bridge-conflicts");

/** Tool names that modify files. */
const FILE_MODIFYING_TOOLS = new Set(["Write", "Edit", "MultiEdit"]);

/**
 * Extract file paths from assistant message content blocks.
 * Looks for Write, Edit, and MultiEdit tool_use blocks with file_path input.
 */
export function extractModifiedFiles(content: ContentBlock[]): string[] {
  const files: string[] = [];
  for (const block of content) {
    if (block.type !== "tool_use") continue;
    if (!FILE_MODIFYING_TOOLS.has(block.name)) continue;
    const filePath = block.input?.file_path;
    if (typeof filePath === "string" && filePath.length > 0) {
      files.push(filePath);
    }
  }
  return files;
}

export interface ConflictCheckDeps {
  /** Get all active sessions. */
  getAllSessionEntries: () => Session[];
  /** Broadcast a message to all browser clients connected to a session. */
  broadcastToBrowsers: (session: Session, msg: BrowserIncomingMessage) => void;
}

/**
 * Record modified files for a session and check for conflicts with other active sessions.
 * When conflicts are detected, broadcasts `file_conflict` messages to both affected sessions.
 */
export function trackFilesAndDetectConflicts(
  session: Session,
  filePaths: string[],
  deps: ConflictCheckDeps,
): void {
  if (filePaths.length === 0) return;

  // Add files to this session's modified set
  for (const fp of filePaths) {
    session.modifiedFiles.add(fp);
  }

  // Check all other active sessions for overlapping files
  const allSessions = deps.getAllSessionEntries();
  for (const other of allSessions) {
    if (other.id === session.id) continue;
    // Only check sessions that have an active CLI connection
    if (!other.cliSocket && !other.codexAdapter) continue;

    const overlapping = filePaths.filter((fp) => other.modifiedFiles.has(fp));
    if (overlapping.length === 0) continue;

    const sessionName = getSessionName(session.id) || `Session ${session.id.slice(0, 8)}`;
    const otherName = getSessionName(other.id) || `Session ${other.id.slice(0, 8)}`;

    log.info(
      { sessionId: session.id, conflictingSessionId: other.id, files: overlapping },
      "File conflict detected between sessions",
    );

    // Notify this session about the conflict with the other session
    deps.broadcastToBrowsers(session, {
      type: "file_conflict",
      sessionId: session.id,
      conflictingSessionId: other.id,
      conflictingSessionName: otherName,
      files: overlapping,
    });

    // Notify the other session about the conflict with this session
    deps.broadcastToBrowsers(other, {
      type: "file_conflict",
      sessionId: other.id,
      conflictingSessionId: session.id,
      conflictingSessionName: sessionName,
      files: overlapping,
    });
  }
}
