/**
 * Edit tool — surgical string replacement in an existing file.
 *
 * Behavior matches Claude SDK's Edit semantics: refuses if `old_string` isn't
 * unique (and `replace_all` is false), so the model can't accidentally edit
 * the wrong occurrence.
 */
import fs from 'fs';
import type { PiTool } from './types.js';
import { safeResolve, displayPath } from './path-safety.js';

export const editTool: PiTool = {
  name: 'Edit',
  description:
    'Replace a unique substring in a file. Fails if `old_string` is not found, or if it appears more than once unless `replace_all` is true.',
  inputSchema: {
    type: 'object',
    properties: {
      file_path: { type: 'string', description: 'File to edit (relative to workspace).' },
      old_string: { type: 'string', description: 'The exact text to find. Include enough surrounding context to make it unique.' },
      new_string: { type: 'string', description: 'Replacement text.' },
      replace_all: { type: 'boolean', description: 'If true, replace every occurrence instead of requiring uniqueness.' },
    },
    required: ['file_path', 'old_string', 'new_string'],
  },

  async run(input, ctx) {
    let abs: string;
    try {
      abs = safeResolve(ctx.cwd, input?.file_path);
    } catch (err: any) {
      return { output: err.message, isError: true };
    }
    if (!fs.existsSync(abs)) {
      return { output: `File not found: ${displayPath(ctx.cwd, abs)}`, isError: true };
    }
    const oldStr = typeof input?.old_string === 'string' ? input.old_string : '';
    const newStr = typeof input?.new_string === 'string' ? input.new_string : '';
    if (!oldStr) return { output: 'old_string is required and cannot be empty.', isError: true };
    if (oldStr === newStr) return { output: 'old_string and new_string are identical — nothing to change.', isError: true };

    const original = fs.readFileSync(abs, 'utf-8');
    const occurrences = original.split(oldStr).length - 1;
    if (occurrences === 0) {
      return {
        output: `Did not find old_string in ${displayPath(ctx.cwd, abs)}. Check whitespace/quoting and re-read the file.`,
        isError: true,
      };
    }
    if (occurrences > 1 && !input?.replace_all) {
      return {
        output: `Found ${occurrences} matches for old_string in ${displayPath(ctx.cwd, abs)}. Add more surrounding context to make it unique, or set replace_all: true.`,
        isError: true,
      };
    }
    const updated = input?.replace_all
      ? original.split(oldStr).join(newStr)
      : original.replace(oldStr, newStr);
    try {
      fs.writeFileSync(abs, updated, 'utf-8');
    } catch (err: any) {
      return { output: `Write failed: ${err.message}`, isError: true };
    }
    return { output: `Edited ${displayPath(ctx.cwd, abs)} (${occurrences} ${occurrences === 1 ? 'match' : 'matches'} replaced).` };
  },
};
