/**
 * Protocol message interfaces for communication with the Bonnie backend.
 * 
 * This file defines the TypeScript interfaces that correspond to the protocol
 * messages defined in bonnie/lib/protocol_messages.py. These interfaces handle
 * the communication protocol between the JupyterLab extension and the backend.
 */

export interface IProtocolMessage {
  message_type: 'request' | 'response';
  call_id: string;
  msg_call_id?: string;
}

// Export ProtocolMessage as a type alias for backward compatibility
export type ProtocolMessage = IProtocolMessage;

export interface IBaseRequest extends IProtocolMessage {
  message_type: 'request';
  username: string;
  // Will be empty on creating new chat.
  // TODO create a nicer hierarchy where chatID is not required for 
  // or listChats messages.
  chatID?: string;
  method: string;
}

export interface IBaseResponse extends IProtocolMessage {
  message_type: 'response';
  value?: any;
  error_type?: string;
}

// ============================================================================
// Chat Management Messages
// ============================================================================

/**
 * Request to list all available chats for a user.
 * This is the initial message sent to bonnie to discover existing chats.
 */
export interface IListChatsRequest extends IBaseRequest {
  method: 'listChats';
  intraspection: any;
  // username is inherited from IBaseRequest
}

/**
 * Response containing the list of available chats for a user.
 */
export interface IListChatsResponse extends IBaseResponse {
  value: {
    chats: Array<{
      chatId: string;  // Note: Server returns camelCase 'chatId', not 'chatID'
      title?: string;
      lastModified: string;
      messageCount: number;
      model?: string;
    }>;
    models?: Array<{ model: string, provider: string }>;  // Available models from the server
  };
}

/**
 * Request to load messages from an existing chat.
 * Uses the new context structure with username and chatID.
 */
export interface ILoadMessagesRequest extends IBaseRequest {
  method: 'loadMessages';
  // username and chatID are inherited from IBaseRequest
}

/**
 * Response containing loaded messages from a chat.
 */
export interface ILoadMessagesResponse extends IBaseResponse {
  value: Array<{
    role: 'user' | 'assistant' | 'system';
    content: string;
    timestamp: string;
    metadata?: any;
  }>;
}

/**
 * Request to create a new chat with specified model and API key.
 * The chatID should be a UUID generated by the frontend.
 */
export interface ICreateNewChatRequest extends IBaseRequest {
  method: 'createNewChat';
  provider: 'gemini' | 'openai' | 'anthropic';
  intraspection?: any;
  root_path?: string;
  api_key?: string;
  openai_api_key?: string;
  anthropic_api_key?: string;
  gemini_api_key?: string;
  model?: string; // Optional model name
}

/**
 * Response to creating a new chat.
 */
export interface ICreateNewChatResponse extends IBaseResponse {
  value: {
    chatID: string;
    model: string;
    created: string;
  };
}

// ============================================================================
// Existing Message Types (Updated)
// ============================================================================

/**
 * Request to continue an existing session.
 * Updated to use new context structure.
 */
export interface IContinueRequest extends IBaseRequest {
  method: 'continue';
  intraspection?: any;
  root_path?: string;
  api_key?: string;
  openai_api_key?: string;
  anthropic_api_key?: string;
  gemini_api_key?: string;
  selected_provider?: string;
}

/**
 * Request containing a user message.
 * Updated to use new context structure.
 */
export interface IUserMessageRequest extends IBaseRequest {
  method: 'userMessage';
  user_message: string;
  opened_tabs?: Array<any>;
  current_notebook?: any;
  mode?: string;
  api_key?: string;
  openai_api_key?: string;
  anthropic_api_key?: string;
  gemini_api_key?: string;
  selected_provider?: string; // Primary model (e.g., "gpt-4o", "claude-4-sonnet")
  secondary_provider?: string; // Secondary model for specialized tasks
  image_parse_provider?: string; // Model for image analysis and parsing
}

/**
 * Request to stop the current LLM generation.
 */
export interface IUserStopRequest extends IBaseRequest {
  method: 'userStop';
}

/**
 * Request to save user settings to the server.
 */
export interface ISaveSettingsRequest extends IBaseRequest {
  method: 'saveSettings';
  openai_api_key?: string;
  gemini_api_key?: string;
  anthropic_api_key?: string;
  voitta_api_key?: string;
  max_messages?: number;
  proxy_port?: number;
  primary_model?: string;
  secondary_provider?: string;
  image_parse_provider?: string;
}

/**
 * Request to retrieve user settings from the server.
 */
export interface IRetrieveSettingsRequest extends IBaseRequest {
  method: 'retrieveSettings';
}

// ============================================================================
// Response Types
// ============================================================================

/**
 * Response to a continue request.
 */
export interface IContinueResponse extends IBaseResponse {
  value: string;
}

/**
 * Error response.
 */
export interface IErrorResponse extends IBaseResponse {
  value: string;
  error_type?: string;
}

/**
 * Success response.
 */
export interface ISuccessResponse extends IBaseResponse {
  value: string;
}

/**
 * Streaming response for LLM content.
 */
export interface IStreamingResponse extends IBaseResponse {
  value: string;
  is_complete: boolean;
  chunk_type: 'text' | 'tool_call' | 'thinking' | 'completion';
}

/**
 * Tool call request from the backend.
 */
export interface IToolCallRequest extends IBaseResponse {
  tool_call_id: string;
  tool_name: string;
  value: {
    tool_call_id: string;
    name: string;
    arguments: any;
  };
  tool_arguments: any;
}

/**
 * Tool response sent back to the backend.
 */
export interface IToolResponse extends IProtocolMessage {
  message_type: 'response';
  value?: any;
  binary_value?: any;
}

/**
 * Response to saving user settings.
 */
export interface ISaveSettingsResponse extends IBaseResponse {
  value: string;
}

/**
 * Response containing user settings from the server.
 */
export interface IRetrieveSettingsResponse extends IBaseResponse {
  openai_api_key?: string;
  gemini_api_key?: string;
  anthropic_api_key?: string;
  voitta_api_key?: string;
  max_messages?: number;
  proxy_port?: number;
  primary_model?: string;
  secondary_provider?: string;
  image_parse_provider?: string;
}


// ============================================================================
// Utility Types
// ============================================================================

/**
 * Union type for all request messages.
 */
export type RequestMessage =
  | IListChatsRequest
  | ILoadMessagesRequest
  | ICreateNewChatRequest
  | IContinueRequest
  | IUserMessageRequest
  | IUserStopRequest
  | ISaveSettingsRequest
  | IRetrieveSettingsRequest;

/**
 * Union type for all response messages.
 */
export type ResponseMessage =
  | IListChatsResponse
  | ILoadMessagesResponse
  | ICreateNewChatResponse
  | IContinueResponse
  | IErrorResponse
  | ISuccessResponse
  | IStreamingResponse
  | IToolCallRequest
  | ISaveSettingsResponse
  | IRetrieveSettingsResponse;

/**
 * Chat model options.
 */
export type ChatModel = 'gemini' | 'openai' | 'anthropic';

/**
 * Chat information for display in UI.
 */
export interface IChatInfo {
  chatId: string;  // Note: Server returns camelCase 'chatId', not 'chatID'
  title?: string;
  lastModified: string;
  messageCount: number;
  model?: string;
}

/**
 * Context identifier using new structure.
 */
export interface IContextID {
  username: string;
  chatID: string;
}

/**
 * Helper function to create a context ID string.
 */
export function createContextIDString(username: string, chatID: string): string {
  return `${username}_${chatID}`;
}

/**
 * Helper function to parse a context ID string.
 */
export function parseContextIDString(contextIDString: string): IContextID {
  const parts = contextIDString.split('_');
  if (parts.length !== 2) {
    throw new Error(`Invalid context ID string: ${contextIDString}`);
  }
  return {
    username: parts[0],
    chatID: parts[1]
  };
}
