import {
  IAgenticaHistoryJson,
  IMicroAgenticaHistoryJson,
} from "@agentica/core";
import {
  AutoBeAnalyzeHistory,
  AutoBeDatabase,
  AutoBeEventSource,
  AutoBeOpenApi,
  AutoBePreliminaryKind,
  AutoBeRealizeCollectorFunction,
  AutoBeRealizeTransformerFunction,
} from "@autobe/interface";
import {
  AutoBeOpenApiEndpointComparator,
  StringUtil,
  writePrismaApplication,
} from "@autobe/utils";
import { HashSet } from "tstl";
import { v7 } from "uuid";

import { AutoBeConfigConstant } from "../../../constants/AutoBeConfigConstant";
import { AutoBeSystemPromptConstant } from "../../../constants/AutoBeSystemPromptConstant";
import { AutoBeState } from "../../../context/AutoBeState";
import { AutoBeInterfaceSchemaProgrammer } from "../../interface/programmers/AutoBeInterfaceSchemaProgrammer";
import { AutoBePreliminaryController } from "../AutoBePreliminaryController";
import { IAutoBePreliminaryRequest } from "../structures/AutoBePreliminaryRequest";
import { IAnalysisSectionEntry } from "../structures/IAnalysisSectionEntry";
import { IAutoBePreliminaryCollection } from "../structures/IAutoBePreliminaryCollection";

export const transformPreliminaryHistory = <Kind extends AutoBePreliminaryKind>(
  preliminary: AutoBePreliminaryController<Kind>,
): IMicroAgenticaHistoryJson[] => {
  const histories: IMicroAgenticaHistoryJson[] = preliminary
    .getKinds()
    .map((key): IMicroAgenticaHistoryJson[] => {
      const newKey: string = key.startsWith("previous")
        ? key.replace("previous", "")
        : key;
      const type: Exclude<AutoBePreliminaryKind, `previous${string}`> = (newKey
        .slice(0, 1)
        .toLowerCase() + newKey.slice(1)) as Exclude<
        AutoBePreliminaryKind,
        `previous${string}`
      >;
      return PreliminaryTransformer[type]({
        source: preliminary.getSource(),
        state: preliminary.getState(),
        all: preliminary.getAll() as IAutoBePreliminaryCollection,
        local: preliminary.getLocal() as IAutoBePreliminaryCollection,
        // biome-ignore lint: intended
        config: preliminary.getConfig() as any,
        previous: key.startsWith("previous"),
        analysisPageOffset: preliminary.getAnalysisPageOffset(),
      });
    })
    .flat();

  // sequence messages
  const systems: IAgenticaHistoryJson.ISystemMessage[] = histories.filter(
    (h) => h.type === "systemMessage",
  );
  const others: IMicroAgenticaHistoryJson[] = histories.filter(
    (h) => h.type !== "systemMessage",
  );
  const messages: IMicroAgenticaHistoryJson[] = [...systems, ...others];

  // previous written value
  const previousWrite: Record<string, unknown> | null =
    preliminary.getPreviousWrite();
  if (previousWrite !== null)
    messages.push(
      createFunctionCallingMessage({
        controller: preliminary.getSource(),
        kind: "write",
        arguments: previousWrite,
      }),
    );
  return messages;
};

namespace PreliminaryTransformer {
  export interface IProps<Kind extends AutoBePreliminaryKind> {
    source: Exclude<AutoBeEventSource, "facade" | "preliminaryAcquire">;
    state: AutoBeState;
    all: Pick<IAutoBePreliminaryCollection, Kind>;
    local: Pick<IAutoBePreliminaryCollection, Kind>;
    config: AutoBePreliminaryController.IConfig<Kind>;
    previous: boolean;
    analysisPageOffset: number;
  }

  export const analysisSections = (
    props: IProps<"analysisSections" | "previousAnalysisSections">,
  ): IMicroAgenticaHistoryJson[] => {
    const kind: "analysisSections" | "previousAnalysisSections" = props.previous
      ? "previousAnalysisSections"
      : "analysisSections";
    const oldbie: Map<number, IAnalysisSectionEntry> = new Map(
      props.local[kind]
        .map((s) => [s.id, s] as const)
        .sort(([a], [b]) => a - b),
    );
    const newbie: IAnalysisSectionEntry[] = props.all[kind]
      .filter((s) => oldbie.has(s.id) === false)
      .sort((a, b) => a.id - b.id);

    const analyze: AutoBeAnalyzeHistory | null = props.previous
      ? props.state.previousAnalyze
      : props.state.analyze;
    const assistant: IAgenticaHistoryJson.IAssistantMessage =
      createAssistantMessage({
        prompt:
          AutoBeSystemPromptConstant.PRELIMINARY_ANALYSIS_SECTION_LOADED.replace(
            "{{PREFIX}}",
            analyze?.prefix ?? "",
          ).replace(
            "{{ACTORS}}",
            analyze?.actors ? toJsonBlock(analyze.actors) : "",
          ),
        previous:
          AutoBeSystemPromptConstant.PRELIMINARY_ANALYSIS_SECTION_PREVIOUS,
        content: Array.from(oldbie.values())
          .map(
            (s) =>
              `### [ID: ${s.id}] ${s.filename} > ${s.unitTitle} > ${s.sectionTitle}\n\n${s.content}`,
          )
          .join("\n\n---\n\n"),
        replace: props.previous
          ? { from: "getAnalysisSections", to: "getPreviousAnalysisSections" }
          : null,
      });
    const pageSize: number = AutoBeConfigConstant.ANALYSIS_PAGE_SIZE;
    const pageStart: number = props.analysisPageOffset;
    const page: IAnalysisSectionEntry[] = newbie.slice(
      pageStart,
      pageStart + pageSize,
    );
    const totalAvailable: number = newbie.length;
    const paginationNote: string =
      totalAvailable > pageStart + pageSize
        ? `\n\n(Showing ${page.length} of ${totalAvailable} available sections, starting from offset ${pageStart}. More sections will appear after you request some of the above.)`
        : "";
    const system: IAgenticaHistoryJson.ISystemMessage = createSystemMessage({
      prompt: AutoBeSystemPromptConstant.PRELIMINARY_ANALYSIS_SECTION,
      previous:
        AutoBeSystemPromptConstant.PRELIMINARY_ANALYSIS_SECTION_PREVIOUS,
      available: formatCompactSectionIndex(page) + paginationNote,
      loaded: Array.from(oldbie.values())
        .map((s) => `- [${s.id}] ${s.sectionTitle}`)
        .join("\n"),
      exhausted:
        page.length === 0
          ? AutoBeSystemPromptConstant.PRELIMINARY_ANALYSIS_SECTION_EXHAUSTED
          : "",
      replace: props.previous
        ? {
            from: "getAnalysisSections",
            to: "getPreviousAnalysisSections",
          }
        : null,
    });
    return props.local[kind].length === 0
      ? [assistant, system]
      : [
          createFunctionCallingMessage({
            controller: props.source,
            kind,
            arguments: {
              thinking: "analysis sections for detailed requirements' analyses",
              request: {
                type: props.previous
                  ? "getPreviousAnalysisSections"
                  : "getAnalysisSections",
                sectionIds: props.local[kind].map((s) => s.id),
              },
            },
          }),
          assistant,
          system,
        ];
  };

  export const databaseSchemas = (
    props: IProps<"databaseSchemas" | "previousDatabaseSchemas">,
  ): IMicroAgenticaHistoryJson[] => {
    const kind: "databaseSchemas" | "previousDatabaseSchemas" = props.previous
      ? "previousDatabaseSchemas"
      : "databaseSchemas";
    const oldbie: Record<string, AutoBeDatabase.IModel> = Object.fromEntries(
      props.local[kind]
        .map((s) => [s.name, s] as const)
        .sort(([a], [b]) => a.localeCompare(b)),
    );
    const newbie: AutoBeDatabase.IModel[] = props.all[kind]
      .filter((s) => oldbie[s.name] === undefined)
      .sort((a, b) => a.name.localeCompare(b.name));

    const assistant: IAgenticaHistoryJson.IAssistantMessage =
      createAssistantMessage({
        prompt: AutoBeSystemPromptConstant.PRELIMINARY_DATABASE_SCHEMA_LOADED,
        previous:
          AutoBeSystemPromptConstant.PRELIMINARY_DATABASE_SCHEMA_PREVIOUS,
        content:
          props.config.database === "ast"
            ? StringUtil.trim`
                ## Database AST Data

                ${toJsonBlock(oldbie)}
              `
            : StringUtil.trim`
                ## Database Schema Files

                \`\`\`prisma
                ${
                  writePrismaApplication({
                    dbms: "postgres",
                    application: {
                      files: [
                        {
                          filename: "all.prisma",
                          namespace: "All",
                          models: Object.values(oldbie),
                        },
                      ],
                    },
                  })["all.prisma"]
                }
                \`\`\
              `,
        replace: props.previous
          ? {
              from: "getDatabaseSchemas",
              to: "getPreviousDatabaseSchemas",
            }
          : null,
      });
    if (props.config.databaseProperty === true)
      assistant.text +=
        "\n\n" +
        StringUtil.trim`
        ### Database Schema Properties

        \`\`\`json
        ${JSON.stringify(
          Object.fromEntries(
            Object.entries(oldbie).map(([k, v]) => [
              k,
              AutoBeInterfaceSchemaProgrammer.getDatabaseSchemaProperties({
                everyModels: props.all.databaseSchemas,
                model: v,
              }).map((p) => p.key),
            ]),
          ),
        )}
        \`\`\`
      `;

    const db: AutoBeDatabase.IApplication | undefined = props.previous
      ? props.state.previousDatabase?.result.data
      : props.state.database?.result.data;
    const system: IAgenticaHistoryJson.ISystemMessage = createSystemMessage({
      prompt: AutoBeSystemPromptConstant.PRELIMINARY_DATABASE_SCHEMA,
      previous: AutoBeSystemPromptConstant.PRELIMINARY_DATABASE_SCHEMA_PREVIOUS,
      available: StringUtil.trim`
        Name | Belonged Group | Stance | Summary
        -----|----------------|--------|---------
        ${newbie
          .map((m) =>
            [
              m.name,
              db?.files.find((f) => f.models.some((md) => md.name === m.name))
                ?.namespace ?? "-",
              m.stance,
              StringUtil.summary(m.description),
            ].join(" | "),
          )
          .join("\n")}
      `,
      loaded: props.local[kind].map((s) => `- ${s.name}`).join("\n"),
      exhausted:
        newbie.length === 0
          ? AutoBeSystemPromptConstant.PRELIMINARY_DATABASE_SCHEMA_EXHAUSTED
          : "",
      replace: props.previous
        ? {
            from: "getDatabaseSchemas",
            to: "getPreviousDatabaseSchemas",
          }
        : null,
    });
    return props.local[kind].length === 0
      ? [assistant, system]
      : [
          createFunctionCallingMessage({
            controller: props.source,
            kind,
            arguments: {
              thinking: "database schemas for DB schema information",
              request: {
                type: props.previous
                  ? "getPreviousDatabaseSchemas"
                  : "getDatabaseSchemas",
                schemaNames: props.local[kind].map((s) => s.name),
              },
            },
          }),
          assistant,
          system,
        ];
  };

  export const interfaceOperations = (
    props: IProps<"interfaceOperations" | "previousInterfaceOperations">,
  ): IMicroAgenticaHistoryJson[] => {
    const kind: "interfaceOperations" | "previousInterfaceOperations" =
      props.previous ? "previousInterfaceOperations" : "interfaceOperations";
    const oldbie: HashSet<AutoBeOpenApi.IEndpoint> = new HashSet(
      props.local[kind]
        .map((o) => ({
          method: o.method,
          path: o.path,
        }))
        .sort(AutoBeOpenApiEndpointComparator.compare),
      AutoBeOpenApiEndpointComparator.hashCode,
      AutoBeOpenApiEndpointComparator.equals,
    );
    const newbie: AutoBeOpenApi.IOperation[] = props.all[kind]
      .filter(
        (o) =>
          oldbie.has({
            method: o.method,
            path: o.path,
          }) === false,
      )
      .sort(AutoBeOpenApiEndpointComparator.compare);

    const assistant: IAgenticaHistoryJson.IAssistantMessage =
      createAssistantMessage({
        prompt:
          AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_OPERATION_LOADED,
        previous:
          AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_OPERATION_PREVIOUS,
        content: toJsonBlock(props.local[kind]),
        replace: props.previous
          ? {
              from: "getInterfaceOperations",
              to: "getPreviousInterfaceOperations",
            }
          : null,
      });
    const system: IAgenticaHistoryJson.ISystemMessage = createSystemMessage({
      prompt: AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_OPERATION,
      previous:
        AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_OPERATION_PREVIOUS,
      available: StringUtil.trim`
        Method | Path | Actor? | Authorization? | Summary
        -------|------|--------|----------------|---------
        ${newbie
          .map((o) =>
            [
              o.method,
              o.path,
              o.authorizationActor ?? "-",
              o.authorizationType ?? "-",
              StringUtil.summary(o.description),
            ].join(" | "),
          )
          .join("\n")}
      `,
      loaded: StringUtil.trim`
        Method | Path
        -------|-------
        ${oldbie
          .toJSON()
          .map((e) => [e.method, e.path].join(" | "))
          .join("\n")}
      `,
      exhausted:
        newbie.length === 0
          ? AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_OPERATION_EXHAUSTED
          : "",
      replace: props.previous
        ? {
            from: "getInterfaceOperations",
            to: "getPreviousInterfaceOperations",
          }
        : null,
    });
    return props.local[kind].length === 0
      ? [assistant, system]
      : [
          createFunctionCallingMessage({
            controller: props.source,
            kind,
            arguments: {
              thinking:
                "interface operations for detailed endpoint information",
              request: {
                type: props.previous
                  ? "getPreviousInterfaceOperations"
                  : "getInterfaceOperations",
                endpoints: oldbie.toJSON(),
              },
            },
          }),
          assistant,
          system,
        ];
  };

  export const interfaceSchemas = (
    props: IProps<"interfaceSchemas" | "previousInterfaceSchemas">,
  ): IMicroAgenticaHistoryJson[] => {
    const kind: "interfaceSchemas" | "previousInterfaceSchemas" = props.previous
      ? "previousInterfaceSchemas"
      : "interfaceSchemas";
    const newbie: Record<string, AutoBeOpenApi.IJsonSchemaDescriptive> = {};
    for (const [k, v] of Object.entries(props.all[kind]).sort(([a], [b]) =>
      a.localeCompare(b),
    ))
      if (props.local[kind][k] === undefined) newbie[k] = v;

    const assistant: IAgenticaHistoryJson.IAssistantMessage =
      createAssistantMessage({
        prompt: AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_SCHEMA_LOADED,
        previous:
          AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_SCHEMA_PREVIOUS,
        content: toJsonBlock(props.local[kind]),
        replace: props.previous
          ? {
              from: "getInterfaceSchemas",
              to: "getPreviousInterfaceSchemas",
            }
          : null,
      });
    const system: IAgenticaHistoryJson.ISystemMessage = createSystemMessage({
      prompt: AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_SCHEMA,
      previous:
        AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_SCHEMA_PREVIOUS,
      available: StringUtil.trim`
        Name | Summary
        -----|---------
        ${Object.entries(newbie)
          .map(([name, schema]) =>
            [name, StringUtil.summary(schema.description)].join(" | "),
          )
          .join("\n")}
      `,
      loaded: Object.keys(props.local[kind])
        .sort()
        .map((k) => `- ${k}`)
        .join("\n"),
      exhausted:
        Object.keys(newbie).length === 0
          ? AutoBeSystemPromptConstant.PRELIMINARY_INTERFACE_SCHEMA_EXHAUSTED
          : "",
      replace: props.previous
        ? {
            from: "getInterfaceSchemas",
            to: "getPreviousInterfaceSchemas",
          }
        : null,
    });
    return Object.keys(props.local[kind]).length === 0
      ? [assistant, system]
      : [
          createFunctionCallingMessage({
            controller: props.source,
            kind,
            arguments: {
              thinking: "interface schemas for detailed schema information",
              request: {
                type: props.previous
                  ? "getPreviousInterfaceSchemas"
                  : "getInterfaceSchemas",
                typeNames: Object.keys(props.local[kind]),
              },
            },
          }),
          assistant,
          system,
        ];
  };

  export const realizeCollectors = (
    props: IProps<"realizeCollectors">,
  ): IMicroAgenticaHistoryJson[] => {
    const oldbie: Record<string, AutoBeRealizeCollectorFunction> =
      Object.fromEntries(
        props.local.realizeCollectors
          .map((c) => [c.plan.dtoTypeName, c] as const)
          .sort(([a], [b]) => a.localeCompare(b)),
      );
    const newbie: AutoBeRealizeCollectorFunction[] = props.all.realizeCollectors
      .filter((c) => oldbie[c.plan.dtoTypeName] === undefined)
      .sort((a, b) => a.plan.dtoTypeName.localeCompare(b.plan.dtoTypeName));

    const assistant: IAgenticaHistoryJson.IAssistantMessage =
      createAssistantMessage({
        prompt: AutoBeSystemPromptConstant.PRELIMINARY_REALIZE_COLLECTOR_LOADED,
        content: toJsonBlock(oldbie),
        replace: null,
        previous: null,
      });
    const system: IAgenticaHistoryJson.ISystemMessage = createSystemMessage({
      prompt: AutoBeSystemPromptConstant.PRELIMINARY_REALIZE_COLLECTOR,
      available: StringUtil.trim`
        DTO Type Name | Database Table | References | Neighbor Collectors
        --------------|----------------|------------|--------------------
        ${newbie
          .map((c) =>
            [
              c.plan.dtoTypeName,
              c.plan.databaseSchemaName,
              c.plan.references.length > 0
                ? `(${c.plan.references.map((r) => r.source).join(", ")})`
                : "-",
              `(${c.neighbors.join(", ")})`,
            ].join(" | "),
          )
          .join("\n")}
      `,
      loaded: props.local.realizeCollectors
        .map((c) => `- ${c.plan.dtoTypeName}`)
        .join("\n"),
      exhausted:
        newbie.length === 0
          ? AutoBeSystemPromptConstant.PRELIMINARY_REALIZE_COLLECTOR_EXHAUSTED
          : "",
      replace: null,
      previous: null,
    });
    return props.local.realizeCollectors.length === 0
      ? [assistant, system]
      : [
          createFunctionCallingMessage({
            controller: props.source,
            kind: "realizeCollectors",
            arguments: {
              thinking: "realize collectors for Create DTO transformation",
              request: {
                type: "getRealizeCollectors",
                dtoTypeNames: props.local.realizeCollectors.map(
                  (c) => c.plan.dtoTypeName,
                ),
              },
            },
          }),
          assistant,
          system,
        ];
  };

  export const complete = (
    _props: IProps<"complete">,
  ): IMicroAgenticaHistoryJson[] => [];

  export const realizeTransformers = (
    props: IProps<"realizeTransformers">,
  ): IMicroAgenticaHistoryJson[] => {
    const oldbie: Record<string, AutoBeRealizeTransformerFunction> =
      Object.fromEntries(
        props.local.realizeTransformers
          .map((t) => [t.plan.dtoTypeName, t] as const)
          .sort(([a], [b]) => a.localeCompare(b)),
      );
    const newbie: AutoBeRealizeTransformerFunction[] =
      props.all.realizeTransformers
        .filter((t) => oldbie[t.plan.dtoTypeName] === undefined)
        .sort((a, b) => a.plan.dtoTypeName.localeCompare(b.plan.dtoTypeName));

    const assistant: IAgenticaHistoryJson.IAssistantMessage =
      createAssistantMessage({
        prompt:
          AutoBeSystemPromptConstant.PRELIMINARY_REALIZE_TRANSFORMER_LOADED,
        content: toJsonBlock(oldbie),
        replace: null,
        previous: null,
      });
    const system: IAgenticaHistoryJson.ISystemMessage = createSystemMessage({
      prompt: AutoBeSystemPromptConstant.PRELIMINARY_REALIZE_TRANSFORMER,
      available: StringUtil.trim`
        DTO Type Name | Database Table | Neighbor Transformers
        --------------|----------------|----------------------
        ${newbie
          .map((t) =>
            [
              t.plan.dtoTypeName,
              t.plan.databaseSchemaName,
              `(${t.neighbors.join(", ")})`,
            ].join(" | "),
          )
          .join("\n")}
      `,
      loaded: props.local.realizeTransformers
        .map((t) => `- ${t.plan.dtoTypeName}`)
        .join("\n"),
      exhausted:
        newbie.length === 0
          ? AutoBeSystemPromptConstant.PRELIMINARY_REALIZE_TRANSFORMER_EXHAUSTED
          : "",
      replace: null,
      previous: null,
    });
    return props.local.realizeTransformers.length === 0
      ? [assistant, system]
      : [
          createFunctionCallingMessage({
            controller: props.source,
            kind: "realizeTransformers",
            arguments: {
              thinking: "realize transformers for response DTO construction",
              request: {
                type: "getRealizeTransformers",
                dtoTypeNames: props.local.realizeTransformers.map(
                  (t) => t.plan.dtoTypeName,
                ),
              },
            },
          }),
          assistant,
          system,
        ];
  };
}

interface IPromptReplace {
  from: Exclude<
    // biome-ignore lint: intended
    IAutoBePreliminaryRequest<any>["request"]["type"],
    `getPrevious${string}`
  >;
  to: Extract<
    // biome-ignore lint: intended
    IAutoBePreliminaryRequest<any>["request"]["type"],
    `getPrevious${string}`
  >;
}

const createAssistantMessage = (props: {
  prompt: string;
  content: string;
  replace: IPromptReplace | null;
  previous: string | null;
}): IAgenticaHistoryJson.IAssistantMessage => {
  let text = props.prompt
    .replaceAll("{{CONTENT}}", props.content)
    .replaceAll(
      "{{PREVIOUS}}",
      props.replace !== null && props.previous !== null ? props.previous : "",
    );
  if (props.replace !== null)
    text = text.replaceAll(props.replace.from, props.replace.to);
  return {
    id: v7(),
    type: "assistantMessage",
    text,
    created_at: new Date().toISOString(),
  };
};

const createSystemMessage = (props: {
  prompt: string;
  available: string;
  loaded: string;
  exhausted: string;
  replace: IPromptReplace | null;
  previous: string | null;
}): IAgenticaHistoryJson.ISystemMessage => {
  let text = props.prompt
    .replaceAll("{{AVAILABLE}}", props.available)
    .replaceAll("{{LOADED}}", props.loaded)
    .replaceAll("{{EXHAUSTED}}", props.exhausted)
    .replaceAll(
      "{{PREVIOUS}}",
      props.replace !== null && props.previous !== null ? props.previous : "",
    );
  if (props.replace !== null)
    text = text.replaceAll(props.replace.from, props.replace.to);
  return {
    id: v7(),
    type: "systemMessage",
    text,
    created_at: new Date().toISOString(),
  };
};

const toJsonBlock = (obj: unknown): string =>
  StringUtil.trim`
      \`\`\`json
      ${JSON.stringify(obj)}
      \`\`\`
    `;

const formatCompactSectionIndex = (
  sections: IAnalysisSectionEntry[],
): string => {
  let result = "";
  let lastFile = "";
  let lastUnit = "";
  let unitSections: string[] = [];
  const flushUnit = () => {
    if (unitSections.length > 0) {
      result += "  " + lastUnit + ": " + unitSections.join(", ") + "\n";
      unitSections = [];
    }
  };
  for (const s of sections) {
    if (s.filename !== lastFile) {
      flushUnit();
      result += "\n[" + s.filename + "]\n";
      lastFile = s.filename;
      lastUnit = "";
    }
    if (s.unitTitle !== lastUnit) {
      flushUnit();
      lastUnit = s.unitTitle;
    }
    unitSections.push(s.id + "." + s.sectionTitle);
  }
  flushUnit();
  return result.trim();
};

// experimenting between assistantMessage and execute types
const createFunctionCallingMessage = <
  Kind extends AutoBePreliminaryKind,
>(props: {
  controller: Exclude<AutoBeEventSource, "facade" | "preliminaryAcquire">;
  kind: Kind | "write";
  arguments: Record<string, unknown>;
}): IAgenticaHistoryJson.IAssistantMessage | IAgenticaHistoryJson.IExecute => ({
  type: "execute",
  id: v7(),
  operation: {
    protocol: "class",
    controller: props.controller,
    function: "process",
    name: "process",
  },
  arguments: props.arguments,
  value: undefined,
  success: true,
  created_at: new Date().toISOString(),
  // type: "assistantMessage",
  // id: v7(),
  // text: StringUtil.trim`
  //   # Function Calling History

  //   Function "${props.function}()" has been called.

  //   Here is the arguments.

  //   Note that, never call the same items again.
  //   As they are loaded onto the memory, you never have to
  //   request none of them again.

  //   \`\`\`json
  //   ${JSON.stringify(props.argument)}
  //   \`\`\`
  // `,
  // created_at: new Date().toISOString(),
});
