// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { ActivityContext } from "./agentInterface.js";
import { DisplayContent } from "./display.js";
import { Entity } from "./memory.js";

export interface AppAction {
    actionName: string;
    schemaName?: string;
    parameters?: Record<string, unknown> | undefined; // the type of the parameters are defined by the AppAgent
}

export type ActionResultError = {
    error: string;
};

export type ActionResultActivityContext = Omit<
    ActivityContext,
    "appAgentName"
> | null;

export type ActionResultSuccess = {
    historyText?: string | undefined;
    displayContent: DisplayContent; // the display content to be appended with "block" mode
    entities: Entity[];
    resultEntity?: Entity | undefined;
    dynamicDisplayId?: string | undefined;
    dynamicDisplayNextRefreshMs?: number | undefined;
    additionalInstructions?: string[] | undefined;
    additionalActions?: AppAction[];
    error?: undefined;

    // REVIEW: activityContext needs to be declarative in the schema instead of generated by the action themselves
    activityContext?: ActionResultActivityContext; // null to clear the activity context
};

export type ActionResultSuccessNoDisplay = Omit<
    ActionResultSuccess,
    "displayContent"
> & {
    displayContent?: undefined;
};

export type ActionResult =
    | ActionResultSuccessNoDisplay
    | ActionResultSuccess
    | ActionResultError;

type EntityField<T> = T extends string
    ? Entity
    : T extends any[]
      ? (EntityField<Required<T[number]>> | undefined)[]
      : T extends object
        ? EntityMap<T>
        : undefined;

export type EntityMap<T> = {
    [Property in keyof T]?: EntityField<T[Property]>;
};

export type ActionEntities<T extends AppAction = AppAction> =
    T["parameters"] extends undefined
        ? undefined
        : EntityMap<Required<T["parameters"]>>;

export type TypeAgentAction<
    T extends AppAction = AppAction,
    Name extends string = string,
> = T extends AppAction
    ? T & {
          schemaName: Name;
          entities?: ActionEntities<T>;
      }
    : never;
