import {
  createProviderToolFactoryWithOutputSchema,
  lazySchema,
  zodSchema,
} from '@ai-sdk/provider-utils';
import { z } from 'zod/v4';

/**
 * Schema for the apply_patch input - what the model sends.
 *
 * Refer the official spec here: https://platform.openai.com/docs/api-reference/responses/create#responses_create-input-input_item_list-item-apply_patch_tool_call
 *
 */
export const applyPatchInputSchema = lazySchema(() =>
  zodSchema(
    z.object({
      callId: z.string(),
      operation: z.discriminatedUnion('type', [
        z.object({
          type: z.literal('create_file'),
          path: z.string(),
          diff: z.string(),
        }),
        z.object({
          type: z.literal('delete_file'),
          path: z.string(),
        }),
        z.object({
          type: z.literal('update_file'),
          path: z.string(),
          diff: z.string(),
        }),
      ]),
    }),
  ),
);

/**
 * Schema for the apply_patch output - what we send back.
 */
export const applyPatchOutputSchema = lazySchema(() =>
  zodSchema(
    z.object({
      status: z.enum(['completed', 'failed']),
      output: z.string().optional(),
    }),
  ),
);

/**
 * Schema for tool arguments (configuration options).
 * The apply_patch tool doesn't require any configuration options.
 */
export const applyPatchArgsSchema = lazySchema(() => zodSchema(z.object({})));

/**
 * Type definitions for the apply_patch operations.
 */
export type ApplyPatchOperation =
  | {
      type: 'create_file';
      /**
       * Path of the file to create relative to the workspace root.
       */
      path: string;
      /**
       * Unified diff content to apply when creating the file.
       */
      diff: string;
    }
  | {
      type: 'delete_file';
      /**
       * Path of the file to delete relative to the workspace root.
       */
      path: string;
    }
  | {
      type: 'update_file';
      /**
       * Path of the file to update relative to the workspace root.
       */
      path: string;
      /**
       * Unified diff content to apply to the existing file.
       */
      diff: string;
    };

/**
 * The apply_patch tool lets GPT-5.1 create, update, and delete files in your
 * codebase using structured diffs. Instead of just suggesting edits, the model
 * emits patch operations that your application applies and then reports back on,
 * enabling iterative, multi-step code editing workflows.
 *
 * The tool factory creates a provider-defined tool that:
 * - Receives patch operations from the model (create_file, update_file, delete_file)
 * - Returns the status of applying those patches (completed or failed)
 *
 */
export const applyPatchToolFactory = createProviderToolFactoryWithOutputSchema<
  {
    /**
     * The unique ID of the apply patch tool call generated by the model.
     */
    callId: string;

    /**
     * The specific create, delete, or update instruction for the apply_patch tool call.
     */
    operation: ApplyPatchOperation;
  },
  {
    /**
     * The status of the apply patch tool call output.
     * - 'completed': The patch was applied successfully.
     * - 'failed': The patch failed to apply.
     */
    status: 'completed' | 'failed';

    /**
     * Optional human-readable log text from the apply patch tool
     * (e.g., patch results or errors).
     */
    output?: string;
  },
  // No configuration options for apply_patch
  {}
>({
  id: 'openai.apply_patch',
  inputSchema: applyPatchInputSchema,
  outputSchema: applyPatchOutputSchema,
});

/**
 * The apply_patch tool lets GPT-5.1 create, update, and delete files in your
 * codebase using structured diffs. Instead of just suggesting edits, the model
 * emits patch operations that your application applies and then reports back on,
 * enabling iterative, multi-step code editing workflows.
 */
export const applyPatch = applyPatchToolFactory;
