import type { JSONObject, LanguageModelV3CallOptions, LanguageModelV3Middleware } from '@ai-sdk/provider';

const isNonEmptyString = (value: unknown): value is string => typeof value === 'string' && value.trim().length > 0;

const getSystemInstructions = (prompt: LanguageModelV3CallOptions['prompt']): string | undefined => {
  const instructions = prompt
    .filter((message) => message.role === 'system')
    .map((message) => message.content)
    .filter(isNonEmptyString);

  return instructions.length > 0 ? instructions.join('\n') : undefined;
};

const hasUnsupportedChatGptCacheRetention = (options: JSONObject): boolean => {
  return options.promptCacheRetention !== undefined || options.prompt_cache_retention !== undefined;
};

/**
 * ChatGPT's Codex backend requires top-level Responses API instructions.
 * The standard OpenAI provider otherwise serializes system prompts as input items.
 */
export function createOpenAiChatGptInstructionsMiddleware(): LanguageModelV3Middleware {
  return {
    specificationVersion: 'v3',
    transformParams: async ({ params }) => {
      const instructions = getSystemInstructions(params.prompt);
      const providerOptions = params.providerOptions ?? {};
      const openAiProviderOptions = providerOptions.openai ?? {};
      const shouldApplyInstructions = !!instructions && !isNonEmptyString(openAiProviderOptions.instructions);
      const shouldStripCacheRetention = hasUnsupportedChatGptCacheRetention(openAiProviderOptions);

      if (!shouldApplyInstructions && !shouldStripCacheRetention) {
        return params;
      }

      const nextOpenAiProviderOptions: JSONObject = { ...openAiProviderOptions };
      delete nextOpenAiProviderOptions.promptCacheRetention;
      delete nextOpenAiProviderOptions.prompt_cache_retention;
      if (shouldApplyInstructions) {
        nextOpenAiProviderOptions.instructions = instructions;
      }

      return {
        ...params,
        prompt: shouldApplyInstructions
          ? params.prompt.filter((message) => message.role !== 'system')
          : params.prompt,
        providerOptions: {
          ...providerOptions,
          openai: nextOpenAiProviderOptions,
        },
      } satisfies LanguageModelV3CallOptions;
    },
  };
}
