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

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

const service = "personal_ai";

const personalAiMetadataSchema = s.looseObject("Additional metadata to pass through to Personal AI.");

const personalAiMessageSchema = s.object(
  "The response returned by Personal AI after message or instruction processing.",
  {
    aiMessage: s.string("The AI's response message."),
    aiScore: s.nullableNumber("The confidence score of the AI response."),
    aiName: s.nullableString("The name of the AI persona that responded."),
    aiPicture: s.nullable(s.url("The image URL for the responding AI persona.")),
    sessionId: s.nullableString("The Personal AI conversation session identifier."),
    sourceApp: s.nullableString("The source application returned by Personal AI."),
    raw: s.looseObject("The raw Personal AI response object."),
  },
  { optional: ["aiScore", "aiName", "aiPicture", "sessionId", "sourceApp"] },
);

const uploadStatusSchema = s.object("The status returned by a Personal AI upload endpoint.", {
  message: s.string("The upload status message returned by Personal AI."),
  raw: s.looseObject("The raw Personal AI response object."),
});

const memorySourceSchema = s.object(
  "The source metadata associated with one memory item.",
  {
    type: s.nullableString("The source type of the memory item."),
    name: s.nullableString("The source name of the memory item."),
  },
  { optional: ["type", "name"] },
);

const memoryTopicSchema = s.looseObject("One topic attached to a Personal AI memory item.");

const memoryItemSchema = s.object(
  "One memory item returned by Personal AI.",
  {
    type: s.nullableString("The Personal AI memory item type."),
    memlevel: s.nullableString("The Personal AI memory level."),
    memlabel: s.nullableString("The memory label generated by Personal AI."),
    startTimeUtc: s.nullableString("The UTC start time for the memory item."),
    source: s.nullable(memorySourceSchema),
    topics: s.nullable(s.array("The topics attached to the memory item.", memoryTopicSchema)),
  },
  {
    optional: ["type", "memlevel", "memlabel", "startTimeUtc", "source", "topics"],
    additionalProperties: true,
  },
);

const uploadMemoryOutputSchema = s.object("The response returned after uploading a memory.", {
  type: s.nullableString("The top-level response type returned by Personal AI."),
  memories: s.array("The memory items returned by Personal AI.", memoryItemSchema),
  raw: s.looseObject("The raw Personal AI response object."),
});

const conversationInputFields = {
  text: s.nonEmptyString("The text to send to the Personal AI persona."),
  domainName: s.nonEmptyString("The hyphenated domain name of the target Personal AI persona."),
  context: s.nonEmptyString("Additional context for the AI response."),
  userName: s.nonEmptyString("The name of the user sending the request."),
  sessionId: s.nonEmptyString("The session identifier used to continue a conversation."),
  sourceName: s.nonEmptyString("The source application name for the inbound message."),
};

export type PersonalAiActionName =
  | "send_message"
  | "send_instruction"
  | "upload_memory"
  | "upload_text_document"
  | "upload_url";

export const personalAiActions: ActionDefinition[] = [
  defineProviderAction(service, {
    name: "send_message",
    description: "Send a message to a Personal AI persona and receive a response.",
    requiredScopes: [],
    inputSchema: s.object(
      "The input payload for sending a Personal AI message.",
      {
        ...conversationInputFields,
        events: s.nonEmptyString("The document name to reference from the persona upload library."),
        isStack: s.boolean("Whether to add the user message to memory."),
        isDraft: s.boolean("Whether to create a copilot draft message."),
        metadata: personalAiMetadataSchema,
      },
      {
        optional: ["context", "userName", "sessionId", "sourceName", "events", "isStack", "isDraft", "metadata"],
      },
    ),
    outputSchema: personalAiMessageSchema,
  }),
  defineProviderAction(service, {
    name: "send_instruction",
    description: "Send a chatgpt or search instruction to a Personal AI persona.",
    requiredScopes: [],
    inputSchema: s.object(
      "The input payload for sending a Personal AI instruction.",
      {
        command: s.stringEnum("The Personal AI instruction command to execute.", ["chatgpt", "search"]),
        ...conversationInputFields,
        isMessage: s.boolean("Whether the instruction should be treated as a message."),
      },
      { optional: ["context", "userName", "sessionId", "sourceName", "isMessage"] },
    ),
    outputSchema: personalAiMessageSchema,
  }),
  defineProviderAction(service, {
    name: "upload_memory",
    description: "Upload one plain text memory to a Personal AI persona memory stack.",
    requiredScopes: [],
    inputSchema: s.object(
      "The input payload for uploading a Personal AI memory.",
      {
        text: s.nonEmptyString("The plain text memory to upload."),
        sourceName: s.nonEmptyString("The source or application name for the memory."),
        domainName: s.nonEmptyString("The hyphenated domain name of the target Personal AI persona."),
        createdTime: s.nonEmptyString("The memory time including timezone."),
        rawFeedText: s.nonEmptyString("The formatted text to store with the memory."),
        tags: s.nonEmptyString("Comma-delimited tags for the memory."),
      },
      { optional: ["createdTime", "rawFeedText", "tags"] },
    ),
    outputSchema: uploadMemoryOutputSchema,
  }),
  defineProviderAction(service, {
    name: "upload_text_document",
    description: "Upload a text document to a Personal AI persona memory library.",
    requiredScopes: [],
    inputSchema: s.object(
      "The input payload for uploading a Personal AI text document.",
      {
        text: s.nonEmptyString("The body text to upload as a document."),
        domainName: s.nonEmptyString("The hyphenated domain name of the target Personal AI persona."),
        title: s.nonEmptyString("The title of the uploaded document."),
        startTime: s.dateTime("The UTC start timestamp for the document."),
        endTime: s.dateTime("The UTC end timestamp for the document."),
        tags: s.nonEmptyString("Comma-delimited tags for the document."),
        isStack: s.boolean("Whether to add the document to memory."),
      },
      { optional: ["title", "startTime", "endTime", "tags", "isStack"] },
    ),
    outputSchema: uploadStatusSchema,
  }),
  defineProviderAction(service, {
    name: "upload_url",
    description: "Upload public URL content to a Personal AI persona memory library.",
    requiredScopes: [],
    inputSchema: s.object(
      "The input payload for uploading URL content to Personal AI.",
      {
        url: s.url("The public URL to upload."),
        domainName: s.nonEmptyString("The hyphenated domain name of the target Personal AI persona."),
        title: s.nonEmptyString("The title of the uploaded content."),
        startTime: s.dateTime("The UTC start timestamp for the content."),
        endTime: s.dateTime("The UTC end timestamp for the content."),
        tags: s.nonEmptyString("Comma-delimited tags for the URL content."),
        isStack: s.boolean("Whether to add the URL content to memory."),
      },
      { optional: ["title", "startTime", "endTime", "tags", "isStack"] },
    ),
    outputSchema: uploadStatusSchema,
  }),
];
