/**
 * Permission-gate helpers for native BooCode write tools. The gate comes from
 * the per-run inference context (`ToolContext.permissionMode`):
 *   plan   — deny the write (read-only); nothing is staged.
 *   bypass — apply the staged change immediately (no queue, no approval).
 *   ask / undefined — leave it in the pending-changes queue for review.
 */
import type { ToolContext } from './types.js';
import { applyOne } from '../pending_changes.js';
import { formatFileDiagnostics } from '../lsp/feedback.js';

/** Result returned when a write is denied under Plan (read-only) mode. */
export function denyReadOnly(operation: string): unknown {
  return {
    status: 'denied',
    operation,
    message: `Read-only (Plan) permission mode — ${operation} is not permitted. Switch to Ask or Bypass to make changes.`,
  };
}

/** Finalize a just-staged change per the permission gate: apply now under Bypass,
 *  otherwise return it as queued for the human to approve. */
export async function finalizeWrite(
  context: ToolContext,
  projectRoot: string,
  change: { id: string; file_path: string; operation: string },
  queuedHint: string,
): Promise<unknown> {
  if (context.permissionMode === 'bypass') {
    const res = await applyOne(context.sql, change.id, projectRoot);
    console.log(
      `[write-gate] bypass apply ${change.operation} ${change.file_path} -> ${res.success ? 'applied' : 'FAILED: ' + (res.error ?? '?')}`,
    );
    let message = res.success
      ? `${change.operation} applied to ${change.file_path}.`
      : `Apply failed for ${change.file_path}: ${res.error ?? 'unknown error'}. Left in the pending queue.`;
    // Post-edit LSP feedback (Crush pattern): on a successful non-delete bypass
    // apply the file is now on disk and the result still flows back into the
    // model's turn, so surface diagnostics it just introduced. Best-effort —
    // `formatFileDiagnostics` returns null on unsupported type / LSP failure.
    if (res.success && change.operation !== 'delete') {
      const diag = await formatFileDiagnostics(change.file_path);
      if (diag) message += `\n\n${diag}`;
    }
    return {
      status: res.success ? 'applied' : 'failed',
      change_id: change.id,
      file_path: change.file_path,
      operation: change.operation,
      message,
    };
  }
  console.log(
    `[write-gate] ${context.permissionMode ?? 'legacy'} queued ${change.operation} ${change.file_path}`,
  );
  return {
    status: 'queued',
    change_id: change.id,
    file_path: change.file_path,
    operation: change.operation,
    message: queuedHint,
  };
}
