import type { ActionDefinition } from "../../core/types.ts";

import { s } from "../../core/json-schema.ts";
import { defineProviderAction } from "../../core/provider-definition.ts";

const service = "anthropic";

const unknownJsonValueSchema = s.unknown("Any JSON value accepted by the Anthropic API.");
const jsonObjectSchema = s.record(unknownJsonValueSchema, {
  description: "A JSON object passed through to the Anthropic API.",
});
const modelSchema = s.looseObject(
  {
    id: s.string("The model identifier."),
    type: s.string("The object type returned by the API."),
    display_name: s.string("A human-readable model name."),
    created_at: s.dateTime("The date and time when the model was created."),
  },
  { description: "An Anthropic model record." },
);
const listModelsInputSchema = s.object(
  "The input payload for listing Anthropic models.",
  {
    before_id: s.string("Returns models before this model identifier."),
    after_id: s.string("Returns models after this model identifier."),
    limit: s.integer("The maximum number of models to return.", { minimum: 1, maximum: 1000 }),
  },
  { optional: ["before_id", "after_id", "limit"] },
);
const listModelsOutputSchema = s.looseObject(
  {
    data: s.array("The list of Anthropic models.", modelSchema),
    has_more: s.boolean("Whether more results are available."),
    first_id: s.nullable(s.string("The first model identifier in this page.")),
    last_id: s.nullable(s.string("The last model identifier in this page.")),
  },
  { description: "The response payload for listing Anthropic models." },
);
const getModelInputSchema = s.object("The input payload for retrieving an Anthropic model.", {
  model_id: s.string("The exact Anthropic model identifier to retrieve."),
});
const contentBlockSchema = s.unknownObject("A structured Anthropic content block.");
const messageContentSchema = s.anyOf("Anthropic message content.", [
  s.string("Plain text message content."),
  s.array("Structured content blocks.", contentBlockSchema, { minItems: 1 }),
]);
const inputMessageSchema = s.looseObject(
  {
    role: s.stringEnum("The role of the message author.", ["user", "assistant"]),
    content: messageContentSchema,
  },
  { description: "An input message in an Anthropic conversation." },
);
const systemContentSchema = s.anyOf("System prompt content.", [
  s.string("Plain text system prompt."),
  s.array("Structured system prompt content blocks.", contentBlockSchema, { minItems: 1 }),
]);
const toolChoiceSchema = s.anyOf("Tool selection strategy for the request.", [
  s.stringEnum("A predefined tool choice mode.", ["auto", "any", "none"]),
  jsonObjectSchema,
]);
const anthropicMetadataSchema = s.looseObject(
  {
    user_id: s.string("An external user identifier for abuse detection."),
  },
  { description: "Metadata about the request." },
);
const createMessageInputSchema = s.looseRequiredObject(
  "The input payload for creating a non-streaming Anthropic message.",
  {
    model: s.string("The Anthropic model identifier to use."),
    max_tokens: s.integer("The maximum number of tokens to generate.", { minimum: 1 }),
    messages: s.array("The ordered conversation history sent to the model.", inputMessageSchema, {
      minItems: 1,
    }),
    system: systemContentSchema,
    metadata: anthropicMetadataSchema,
    stop_sequences: s.array("Custom text sequences that stop generation.", s.string("A stop sequence.")),
    stream: s.boolean(
      "Whether to request a streaming response. This connector only accepts false or an omitted value.",
    ),
    temperature: s.number("The sampling temperature.", { minimum: 0, maximum: 1 }),
    thinking: jsonObjectSchema,
    tool_choice: toolChoiceSchema,
    tools: s.array("Tools available to the model.", jsonObjectSchema),
    top_k: s.integer("Only sample from the top K options for each token.", { minimum: 0 }),
    top_p: s.number("The nucleus sampling threshold.", { minimum: 0, maximum: 1 }),
  },
  {
    optional: [
      "system",
      "metadata",
      "stop_sequences",
      "stream",
      "temperature",
      "thinking",
      "tool_choice",
      "tools",
      "top_k",
      "top_p",
    ],
  },
);
const messageUsageSchema = s.looseObject(
  {
    input_tokens: s.integer("The number of input tokens consumed."),
    output_tokens: s.integer("The number of output tokens generated."),
  },
  { description: "Token usage information." },
);
const messageOutputSchema = s.looseObject(
  {
    id: s.string("The message identifier."),
    type: s.string("The object type returned by the API."),
    role: s.string("The role of the returned message."),
    model: s.string("The model used to generate the response."),
    content: s.array("Content blocks generated by the model.", contentBlockSchema),
    stop_reason: s.nullable(s.string("The reason generation stopped.")),
    stop_sequence: s.nullable(s.string("The stop sequence that ended generation.")),
    usage: messageUsageSchema,
  },
  { description: "The response payload for an Anthropic message." },
);
const countMessageTokensInputSchema = s.looseRequiredObject(
  "The input payload for counting tokens in an Anthropic message request.",
  {
    model: s.string("The Anthropic model identifier to use."),
    messages: s.array("The ordered conversation history to count.", inputMessageSchema, {
      minItems: 1,
    }),
    system: systemContentSchema,
    thinking: jsonObjectSchema,
    tool_choice: toolChoiceSchema,
    tools: s.array("Tools available to the model.", jsonObjectSchema),
  },
  { optional: ["system", "thinking", "tool_choice", "tools"] },
);
const countMessageTokensOutputSchema = s.looseObject(
  {
    input_tokens: s.integer("The number of input tokens counted for the request."),
  },
  { description: "The response payload for counting Anthropic message tokens." },
);

export const anthropicActions: ActionDefinition[] = [
  defineProviderAction(service, {
    name: "list_models",
    description: "List Anthropic models available to the current API key.",
    requiredScopes: [],
    inputSchema: listModelsInputSchema,
    outputSchema: listModelsOutputSchema,
  }),
  defineProviderAction(service, {
    name: "get_model",
    description: "Fetch metadata for one Anthropic model.",
    requiredScopes: [],
    inputSchema: getModelInputSchema,
    outputSchema: modelSchema,
  }),
  defineProviderAction(service, {
    name: "create_message",
    description: "Create a non-streaming Anthropic message.",
    requiredScopes: [],
    inputSchema: createMessageInputSchema,
    outputSchema: messageOutputSchema,
  }),
  defineProviderAction(service, {
    name: "count_message_tokens",
    description: "Count input tokens for an Anthropic message request.",
    requiredScopes: [],
    inputSchema: countMessageTokensInputSchema,
    outputSchema: countMessageTokensOutputSchema,
  }),
];
