import { z } from 'zod';
import type { ToolDef, ToolContext } from './types.js';
import { rewindOne } from '../pending_changes.js';

const RewindInput = z.object({
  change_id: z.string().uuid().optional(),
  all: z.boolean().optional(),
});
type RewindInputT = z.infer<typeof RewindInput>;

export const rewindTool: ToolDef<RewindInputT> = {
  name: 'rewind',
  description:
    'Revert applied changes. Provide change_id to revert a specific change, ' +
    'or set all=true to revert all applied changes for the session (in reverse order).',
  inputSchema: RewindInput,
  jsonSchema: {
    type: 'function',
    function: {
      name: 'rewind',
      description:
        'Revert applied changes. Provide change_id to revert a specific change, ' +
        'or set all=true to revert all applied changes for the session (in reverse order).',
      parameters: {
        type: 'object',
        properties: {
          change_id: { type: 'string', format: 'uuid', description: 'ID of a specific change to revert' },
          all: { type: 'boolean', description: 'If true, revert all applied changes for this session' },
        },
        required: [],
      },
    },
  },
  async execute(input: RewindInputT, projectRoot: string, context: ToolContext): Promise<unknown> {
    if (input.change_id) {
      const result = await rewindOne(context.sql, input.change_id, projectRoot);
      return {
        results: [result],
        message: result.success
          ? `Reverted change ${input.change_id} (${result.operation} on ${result.file_path}).`
          : `Failed to revert: ${result.error}`,
      };
    }

    if (input.all) {
      // Rewind all applied changes for this session in reverse order
      const applied = await context.sql<{ id: string }[]>`
        SELECT id FROM pending_changes
        WHERE session_id = ${context.sessionId} AND status = 'applied'
        ORDER BY created_at DESC
      `;
      const results = [];
      for (const row of applied) {
        results.push(await rewindOne(context.sql, row.id, projectRoot));
      }
      const succeeded = results.filter((r) => r.success).length;
      return {
        total: results.length,
        succeeded,
        failed: results.length - succeeded,
        results,
        message:
          results.length === 0
            ? 'No applied changes to revert.'
            : `Reverted ${succeeded}/${results.length} changes.`,
      };
    }

    return { error: 'Provide either change_id or all=true.' };
  },
};
