import * as crypto from 'node:crypto';

export interface SessionManagerLike {
  startSession(c: {
    name?: string;
    engine?: string;
    model?: string;
    cwd?: string;
    systemPrompt?: string;
    permissionMode?: string;
  }): Promise<{ name: string }>;
  sendMessage(name: string, msg: string): Promise<{ output: string }>;
  stopSession(name: string): Promise<void>;
}

export interface FixerArgs {
  worktreePath: string;
  failingCommand: string;
  tail: string;
}

const SYSTEM = `
You are a fix-on-failure agent for an ultraapp build. The user will give you
the worktree path, a failing shell command, and the last 200 lines of its
output. Your job: edit files to make the failing command succeed. Don't change
application behaviour, only fix mechanical errors (types, imports, dockerfile
syntax, missing files). When done, reply with the literal marker line:

[FIX-ROUND-DONE]

If the failure is genuinely caused by a behaviour problem you can't fix
without changing semantics, reply with:

[FIX-ROUND-GIVEUP] reason: <one sentence>

Then [FIX-ROUND-DONE].
`.trim();

const COMPLETE_RE = /\[FIX-ROUND-DONE\]/;
const MAX_ATTEMPTS = 5;

export async function spawnFixerSession(args: FixerArgs): Promise<void> {
  const { SessionManager } = await import('../session-manager.js');
  const sm = new SessionManager();
  await spawnFixerSessionWith(sm as unknown as SessionManagerLike, args);
}

export async function spawnFixerSessionWith(sm: SessionManagerLike, args: FixerArgs): Promise<void> {
  const sessionName = `ua-fix-${crypto.randomBytes(4).toString('hex')}`;
  await sm.startSession({
    name: sessionName,
    engine: 'claude',
    model: 'claude-opus-4-7',
    cwd: args.worktreePath,
    systemPrompt: SYSTEM,
    permissionMode: 'bypassPermissions',
  });
  try {
    const prompt = `Failing command: \`${args.failingCommand}\`\n\nLast output:\n\n\`\`\`\n${args.tail}\n\`\`\`\n\nFix it. End with [FIX-ROUND-DONE].`;
    let attempts = 0;
    while (attempts++ < MAX_ATTEMPTS) {
      const r = await sm.sendMessage(
        sessionName,
        attempts === 1 ? prompt : 'continue. when done, output [FIX-ROUND-DONE].',
      );
      if (COMPLETE_RE.test(r.output)) break;
    }
  } finally {
    await sm.stopSession(sessionName).catch(() => {});
  }
}
