import {
  ReasoningEffortEnum,
  OpenAIMessageInput,
  MessageRole,
  LogitBiasItem,
  StreamOptions,
  AnthropicThinkingParamInput,
  ToolChoiceEnum,
  LLMToolInput,
  ToolChoice,
  ToolCall,
  ModelProvider,
  LLMGetAllMetadataResponse,
  Api,
  AgenticPromptRunResponse,
  OpenAIMessageItem,
  PromptExperimentDetail,
  PromptExperimentSummary,
} from "@/lib/api-client/api-client";

// Frontend tool type that extends LLMToolInput with an id for UI purposes
type FrontendTool = LLMToolInput & { id: string };

const promptClassificationEnum = {
  EVAL: "eval",
  DEFAULT: "default",
};

type PromptAction =
  | { type: "addPrompt" }
  | { type: "deletePrompt"; payload: { id: string } }
  | { type: "duplicatePrompt"; payload: { id: string } }
  | { type: "hydratePrompt"; payload: { promptData: Partial<PromptType> } }
  | { type: "clearPrompts" }
  | { type: "hydrateNotebookState"; payload: { prompts: PromptType[]; keywords: Map<string, string> } }
  | { type: "updatePromptName"; payload: { promptId: string; name: string } }
  | {
      type: "updatePromptProvider";
      payload: { promptId: string; modelProvider: ModelProvider | "" };
    }
  | {
      type: "updatePromptModelName";
      payload: { promptId: string; modelName: string };
    }
  | {
      type: "updatePrompt";
      payload: { promptId: string; prompt: Partial<PromptType> };
    }
  | {
      type: "updateBackendPrompts";
      payload: { prompts: LLMGetAllMetadataResponse[] };
    }
  | { type: "addMessage"; payload: { parentId: string } }
  | { type: "deleteMessage"; payload: { parentId: string; id: string } }
  | { type: "duplicateMessage"; payload: { parentId: string; id: string } }
  | {
      type: "hydrateMessage";
      payload: { parentId: string; messageData: Partial<MessageType> };
    }
  | {
      type: "editMessage";
      payload: { parentId: string; id: string; content: string };
    }
  | {
      type: "editMessageToolCalls";
      payload: { parentId: string; id: string; toolCalls: ToolCall[] | null };
    }
  | {
      type: "editMessageToolCallId";
      payload: { parentId: string; id: string; toolCallId: string | null };
    }
  | {
      type: "changeMessageRole";
      payload: { parentId: string; id: string; role: string };
    }
  | {
      type: "updateKeywords";
      payload: { id: string; messageKeywords: string[] };
    }
  | {
      type: "extractPromptVariables";
      payload: { promptId: string; variables: string[] };
    }
  | {
      type: "updateKeywordValue";
      payload: { keyword: string; value: string };
    }
  | {
      type: "runPrompt";
      payload: { promptId: string };
    }
  | {
      type: "updateModelParameters";
      payload: { promptId: string; modelParameters: ModelParametersType };
    }
  | {
      type: "updateResponseFormat";
      payload: { promptId: string; responseFormat: string | undefined };
    }
  | { type: "addTool"; payload: { promptId: string } }
  | { type: "deleteTool"; payload: { promptId: string; toolId: string } }
  | {
      type: "updateTool";
      payload: {
        parentId: string;
        toolId: string;
        tool: Partial<FrontendTool>;
      };
    }
  | { type: "expandTools"; payload: { parentId: string } }
  | {
      type: "updateToolChoice";
      payload: { promptId: string; toolChoice: ToolChoiceEnum | ToolChoice };
    }
  | {
      type: "moveMessage";
      payload: { parentId: string; fromIndex: number; toIndex: number };
    };

// The id is used in the FE, but may not need to be stored in BE.
interface MessageType extends OpenAIMessageInput {
  id: string;
  disabled: boolean;
}

type ModelParametersType = {
  temperature?: number | null; // 0 < temperature <= 1 (or 2?)
  top_p?: number | null; // 0 < top_p <= 1
  timeout?: number | null; // In milliseconds
  stream?: boolean; // Whether to stream the response, defautl false
  stream_options?: StreamOptions | null;
  max_tokens?: number | null; // Length limit of generated response > 0
  max_completion_tokens?: number | null; // ??
  frequency_penalty?: number | null; // -2 < frequency_penalty <= 2
  presence_penalty?: number | null; // -2 < presence_penalty <= 2, default 0
  stop?: string | null; // Stop sequence
  seed?: number | null; // Random seed
  reasoning_effort?: ReasoningEffortEnum | null;
  // The following do not appear in the UI
  logprobs?: boolean | null; //Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each output token returned in the content of message.
  top_logprobs?: number | null; //An integer between 0 and 5 specifying the number of most likely tokens to return at each token position, each with an associated log probability. logprobs must be set to true if this parameter is used.
  logit_bias?: LogitBiasItem[] | null;
  thinking?: AnthropicThinkingParamInput | null;
};

type PromptType = {
  id: string; // name + timestamp, probably
  classification: string;
  name: string;
  created_at: string | undefined;
  modelName: string;
  modelProvider: ModelProvider | "";
  messages: MessageType[];
  modelParameters: ModelParametersType;
  runResponse: AgenticPromptRunResponse | null; // The response from the last run
  responseFormat: string | undefined; //LLMResponseSchemaInput
  tools: FrontendTool[]; //LLMToolOutput
  toolChoice?: ToolChoiceEnum | ToolChoice;
  // tags: Array<string>; // TODO
  running?: boolean; // Whether the prompt is running
  version?: number | null; // Unsaved prompts have no version
  isDirty?: boolean; // Whether the prompt has been modified from its saved version
  needsSave?: boolean; // Whether the prompt needs to be saved (dirty or new with user content)
  savedSnapshot: string | null; // JSON snapshot of saveable fields at last save/load; null = never saved
};

interface PromptPlaygroundState {
  keywords: Map<string, string>;
  keywordTracker: Map<string, Array<string>>;
  prompts: PromptType[];
  backendPrompts: LLMGetAllMetadataResponse[];
}

interface MessageComponentProps {
  id: string;
  parentId: string;
  role?: string;
  defaultContent?: string | OpenAIMessageItem[];
  content: string | OpenAIMessageItem[] | "";
  toolCalls?: ToolCall[] | null;
  toolCallId?: string | null;
  dragHandleProps?: Record<string, unknown>;
}

interface PromptComponentProps {
  prompt: PromptType;
  useIconOnlyMode: boolean;
  highlightCost?: boolean;
}

interface OutputFieldProps {
  promptId: string;
  running: boolean;
  runResponse: AgenticPromptRunResponse | null;
  responseFormat: string | undefined;
  dialogOpen: boolean;
  onCloseDialog: () => void;
  highlightCost?: boolean;
}

interface SavePromptDialogProps {
  open: boolean;
  setOpen: (open: boolean) => void;
  prompt: PromptType;
  initialName?: string;
}

interface VersionSubmenuProps {
  open: boolean;
  promptName: string;
  taskId: string;
  apiClient: Api<unknown>;
  onVersionSelect: (version: number) => void;
  onClose: () => void;
  anchorEl: HTMLElement | null;
}

const MESSAGE_ROLE_OPTIONS: MessageRole[] = ["system", "user", "assistant", "tool"];

/**
 * Data resolved by the wrapper component before the inner playground mounts.
 * Eliminates the need for hydration useEffects — the inner component
 * initializes all state directly from this object.
 */
interface PlaygroundInitialData {
  /** Prompts to load into the reducer (empty array = blank playground) */
  prompts: PromptType[];
  /** Keyword variable mappings restored from notebook state */
  keywords: Map<string, string>;
  /** Display name for the notebook header */
  notebookName: string;
  /** Experiment config restored from notebook state or experiment mode params */
  experimentConfig: Partial<PromptExperimentDetail> | null;
  /** Matching experiment runs for the history sidebar */
  experimentRuns: PromptExperimentSummary[];
  /** Whether experiment config mode is active */
  isConfigMode: boolean;
  /** Serialized state string for auto-save dirty detection baseline */
  autoSaveBaseline: string;
  /** Source info for the mount-time toast and analytics event */
  source: {
    type: "notebook" | "span" | "experiment" | "url-prompt" | "blank";
    label: string;
  };
}

type ExperimentExecutionState =
  | { status: "idle" }
  | { status: "starting" }
  | { status: "running"; experimentId: string }
  | { status: "completed"; experimentId: string }
  | { status: "error" };

export {
  MESSAGE_ROLE_OPTIONS,
  MessageComponentProps,
  MessageType,
  ModelParametersType,
  PromptType,
  PromptComponentProps,
  PromptPlaygroundState,
  PromptAction,
  promptClassificationEnum,
  OutputFieldProps,
  SavePromptDialogProps,
  FrontendTool,
  VersionSubmenuProps,
  PlaygroundInitialData,
  ExperimentExecutionState,
};
