/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import {
  type CompressionStatus,
  type GeminiCLIExtension,
  type MCPServerConfig,
  type ThoughtSummary,
  type SerializableConfirmationDetails,
  type ToolResultDisplay,
  type ToolDisplay,
  type RetrieveUserQuotaResponse,
  type SkillDefinition,
  type AgentDefinition,
  type ApprovalMode,
  type Kind,
  type AnsiOutput,
  CoreToolCallStatus,
  checkExhaustive,
  type SubagentActivityItem,
} from '@google/gemini-cli-core';
import type { PartListUnion } from '@google/genai';
import { type ReactNode } from 'react';

export { CoreToolCallStatus };
export type {
  ThoughtSummary,
  SkillDefinition,
  SerializableConfirmationDetails,
  ToolResultDisplay,
};

export enum AuthState {
  // Attempting to authenticate or re-authenticate
  Unauthenticated = 'unauthenticated',
  // Auth dialog is open for user to select auth method
  Updating = 'updating',
  // Waiting for user to input API key
  AwaitingApiKeyInput = 'awaiting_api_key_input',
  // Successfully authenticated
  Authenticated = 'authenticated',
  // Waiting for the user to restart after a login
  AwaitingLoginRestart = 'awaiting_login_restart',
}

// Only defining the state enum needed by the UI
export enum StreamingState {
  Idle = 'idle',
  Responding = 'responding',
  WaitingForConfirmation = 'waiting_for_confirmation',
}

// Copied from server/src/core/turn.ts for CLI usage
export enum GeminiEventType {
  Content = 'content',
  ToolCallRequest = 'tool_call_request',
  // Add other event types if the UI hook needs to handle them
}

export enum ToolCallStatus {
  Pending = 'Pending',
  Canceled = 'Canceled',
  Confirming = 'Confirming',
  Executing = 'Executing',
  Success = 'Success',
  Error = 'Error',
}

/**
 * Maps core tool call status to a simplified UI status.
 */
export function mapCoreStatusToDisplayStatus(
  coreStatus: CoreToolCallStatus,
): ToolCallStatus {
  switch (coreStatus) {
    case CoreToolCallStatus.Validating:
      return ToolCallStatus.Pending;
    case CoreToolCallStatus.AwaitingApproval:
      return ToolCallStatus.Confirming;
    case CoreToolCallStatus.Executing:
      return ToolCallStatus.Executing;
    case CoreToolCallStatus.Success:
      return ToolCallStatus.Success;
    case CoreToolCallStatus.Cancelled:
      return ToolCallStatus.Canceled;
    case CoreToolCallStatus.Error:
      return ToolCallStatus.Error;
    case CoreToolCallStatus.Scheduled:
      return ToolCallStatus.Pending;
    default:
      return checkExhaustive(coreStatus);
  }
}

/**
 * --- TYPE GUARDS ---
 */

export const isTodoList = (res: unknown): res is { todos: unknown[] } =>
  typeof res === 'object' && res !== null && 'todos' in res;

export const isAnsiOutput = (res: unknown): res is AnsiOutput =>
  Array.isArray(res) && (res.length === 0 || Array.isArray(res[0]));

export interface ToolCallEvent {
  type: 'tool_call';
  status: CoreToolCallStatus;
  callId: string;
  name: string;
  args: Record<string, never>;
  resultDisplay: ToolResultDisplay | undefined;
  confirmationDetails: SerializableConfirmationDetails | undefined;
  correlationId?: string;
}

export interface IndividualToolCallDisplay {
  callId: string;
  parentCallId?: string;
  name: string;
  args?: Record<string, unknown>;
  description: string;
  display?: ToolDisplay;
  resultDisplay: ToolResultDisplay | undefined;
  status: CoreToolCallStatus;
  // True when the tool was initiated directly by the user (slash/@/shell flows).
  isClientInitiated?: boolean;
  kind?: Kind;
  confirmationDetails: SerializableConfirmationDetails | undefined;
  renderOutputAsMarkdown?: boolean;
  ptyId?: number;
  outputFile?: string;
  correlationId?: string;
  approvalMode?: ApprovalMode;
  progressMessage?: string;
  originalRequestName?: string;
  progress?: number;
  progressTotal?: number;
  subagentHistory?: SubagentActivityItem[];
}

export interface CompressionProps {
  isPending: boolean;
  originalTokenCount: number | null;
  newTokenCount: number | null;
  compressionStatus: CompressionStatus | null;
}

export interface ExportSessionProps {
  isPending: boolean;
  targetPath?: string;
}

/**
 * For use when you want no icon.
 */
export const emptyIcon = '  ';

export interface HistoryItemBase {
  text?: string; // Text content for user/gemini/info/error messages
}

export type HistoryItemUser = HistoryItemBase & {
  type: 'user';
  text: string;
};

export type HistoryItemGemini = HistoryItemBase & {
  type: 'gemini';
  text: string;
};

export type HistoryItemGeminiContent = HistoryItemBase & {
  type: 'gemini_content';
  text: string;
};

export type HistoryItemInfo = HistoryItemBase & {
  type: 'info';
  text: string;
  secondaryText?: string;
  source?: string;
  icon?: string;
  color?: string;
  marginBottom?: number;
};

export type HistoryItemError = HistoryItemBase & {
  type: 'error';
  text: string;
};

export type HistoryItemWarning = HistoryItemBase & {
  type: 'warning';
  text: string;
};

export type HistoryItemAbout = HistoryItemBase & {
  type: 'about';
  cliVersion: string;
  osVersion: string;
  sandboxEnv: string;
  modelVersion: string;
  selectedAuthType: string;
  gcpProject: string;
  ideClient: string;
  userEmail?: string;
  tier?: string;
};

export type HistoryItemHelp = HistoryItemBase & {
  type: 'help';
  timestamp: Date;
};

export interface HistoryItemQuotaBase extends HistoryItemBase {
  selectedAuthType?: string;
  userEmail?: string;
  tier?: string;
  currentModel?: string;
  pooledRemaining?: number;
  pooledLimit?: number;
  pooledResetTime?: string;
}

export interface QuotaStats {
  remaining: number | undefined;
  limit: number | undefined;
  resetTime?: string;
}

export type HistoryItemStats = HistoryItemQuotaBase & {
  type: 'stats';
  duration: string;
  quotas?: RetrieveUserQuotaResponse;
  creditBalance?: number;
};

export type HistoryItemModelStats = HistoryItemQuotaBase & {
  type: 'model_stats';
};

export type HistoryItemToolStats = HistoryItemBase & {
  type: 'tool_stats';
};

export type HistoryItemModel = HistoryItemBase & {
  type: 'model';
  model: string;
};

export type HistoryItemQuit = HistoryItemBase & {
  type: 'quit';
  duration: string;
};

export type HistoryItemToolGroup = HistoryItemBase & {
  type: 'tool_group';
  tools: IndividualToolCallDisplay[];
  borderTop?: boolean;
  borderBottom?: boolean;
  borderColor?: string;
  borderDimColor?: boolean;
};

export type ToolDisplayItem = ToolDisplay & {
  status: CoreToolCallStatus;
  originalRequestName?: string;
};

export type HistoryItemToolDisplayGroup = HistoryItemBase & {
  type: 'tool_display_group';
  tools: ToolDisplayItem[];
  borderTop?: boolean;
  borderBottom?: boolean;
  borderColor?: string;
  borderDimColor?: boolean;
};

export type HistoryItemUserShell = HistoryItemBase & {
  type: 'user_shell';
  text: string;
};

export type HistoryItemCompression = HistoryItemBase & {
  type: 'compression';
  compression: CompressionProps;
};

export type HistoryItemExportSession = HistoryItemBase & {
  type: 'export_session';
  exportSession: ExportSessionProps;
};

export type HistoryItemExtensionsList = HistoryItemBase & {
  type: 'extensions_list';
  extensions: GeminiCLIExtension[];
};

export interface ChatDetail {
  name: string;
  mtime: string;
}

export type HistoryItemThinking = HistoryItemBase & {
  type: 'thinking';
  thought: ThoughtSummary;
};

export type HistoryItemHint = HistoryItemBase & {
  type: 'hint';
  text: string;
};

export type HistoryItemChatList = HistoryItemBase & {
  type: 'chat_list';
  chats: ChatDetail[];
};

export type HistoryItemSubagent = HistoryItemBase & {
  type: 'subagent';
  agentName: string;
  history: SubagentActivityItem[];
};

export interface ToolDefinition {
  name: string;
  displayName: string;
  description?: string;
}

export type HistoryItemToolsList = HistoryItemBase & {
  type: 'tools_list';
  tools: ToolDefinition[];
  showDescriptions: boolean;
};

export type HistoryItemSkillsList = HistoryItemBase & {
  type: 'skills_list';
  skills: SkillDefinition[];
  showDescriptions: boolean;
};

export type AgentDefinitionJson = Pick<
  AgentDefinition,
  'name' | 'displayName' | 'description' | 'kind'
>;

export type HistoryItemAgentsList = HistoryItemBase & {
  type: 'agents_list';
  agents: AgentDefinitionJson[];
};

// JSON-friendly types for using as a simple data model showing info about an
// MCP Server.
export interface JsonMcpTool {
  serverName: string;
  name: string;
  description?: string;
  schema?: {
    parametersJsonSchema?: unknown;
    parameters?: unknown;
  };
}

export interface JsonMcpPrompt {
  serverName: string;
  name: string;
  description?: string;
}

export interface JsonMcpResource {
  serverName: string;
  name?: string;
  uri?: string;
  mimeType?: string;
  description?: string;
}

export type HistoryItemGemmaStatus = HistoryItemBase & {
  type: 'gemma_status';
  binaryInstalled: boolean;
  binaryPath: string | null;
  modelName: string;
  modelDownloaded: boolean;
  serverRunning: boolean;
  serverPid: number | null;
  serverPort: number;
  settingsEnabled: boolean;
  allPassing: boolean;
};

export type HistoryItemMcpStatus = HistoryItemBase & {
  type: 'mcp_status';
  servers: Record<string, MCPServerConfig>;
  tools: JsonMcpTool[];
  prompts: JsonMcpPrompt[];
  resources: JsonMcpResource[];
  authStatus: Record<
    string,
    'authenticated' | 'expired' | 'unauthenticated' | 'not-configured'
  >;
  enablementState: Record<
    string,
    {
      enabled: boolean;
      isSessionDisabled: boolean;
      isPersistentDisabled: boolean;
    }
  >;
  errors: Record<string, string>;
  blockedServers: Array<{ name: string; extensionName: string }>;
  discoveryInProgress: boolean;
  connectingServers: string[];
  showDescriptions: boolean;
  showSchema: boolean;
};

// Individually exported types extending HistoryItemBase
export type HistoryItemWithoutId =
  | HistoryItemUser
  | HistoryItemUserShell
  | HistoryItemGemini
  | HistoryItemGeminiContent
  | HistoryItemInfo
  | HistoryItemError
  | HistoryItemWarning
  | HistoryItemAbout
  | HistoryItemHelp
  | HistoryItemToolGroup
  | HistoryItemToolDisplayGroup
  | HistoryItemStats
  | HistoryItemModelStats
  | HistoryItemToolStats
  | HistoryItemModel
  | HistoryItemQuit
  | HistoryItemCompression
  | HistoryItemExportSession
  | HistoryItemExtensionsList
  | HistoryItemToolsList
  | HistoryItemSkillsList
  | HistoryItemAgentsList
  | HistoryItemMcpStatus
  | HistoryItemGemmaStatus
  | HistoryItemChatList
  | HistoryItemThinking
  | HistoryItemHint
  | HistoryItemSubagent;

export type HistoryItem = HistoryItemWithoutId & { id: number };

// Message types used by internal command feedback (subset of HistoryItem types)
export enum MessageType {
  INFO = 'info',
  ERROR = 'error',
  WARNING = 'warning',
  USER = 'user',
  ABOUT = 'about',
  HELP = 'help',
  STATS = 'stats',
  MODEL_STATS = 'model_stats',
  TOOL_STATS = 'tool_stats',
  QUIT = 'quit',
  GEMINI = 'gemini',
  COMPRESSION = 'compression',
  EXPORT_SESSION = 'export_session',
  EXTENSIONS_LIST = 'extensions_list',
  TOOLS_LIST = 'tools_list',
  SKILLS_LIST = 'skills_list',
  AGENTS_LIST = 'agents_list',
  MCP_STATUS = 'mcp_status',
  GEMMA_STATUS = 'gemma_status',
  CHAT_LIST = 'chat_list',
  HINT = 'hint',
}

// Simplified message structure for internal feedback
export type Message =
  | {
      type: MessageType.INFO | MessageType.ERROR | MessageType.USER;
      content: string; // Renamed from text for clarity in this context
      timestamp: Date;
    }
  | {
      type: MessageType.ABOUT;
      timestamp: Date;
      cliVersion: string;
      osVersion: string;
      sandboxEnv: string;
      modelVersion: string;
      selectedAuthType: string;
      gcpProject: string;
      ideClient: string;
      userEmail?: string;
      content?: string; // Optional content, not really used for ABOUT
    }
  | {
      type: MessageType.HELP;
      timestamp: Date;
      content?: string; // Optional content, not really used for HELP
    }
  | {
      type: MessageType.STATS;
      timestamp: Date;
      duration: string;
      content?: string;
    }
  | {
      type: MessageType.MODEL_STATS;
      timestamp: Date;
      content?: string;
    }
  | {
      type: MessageType.TOOL_STATS;
      timestamp: Date;
      content?: string;
    }
  | {
      type: MessageType.QUIT;
      timestamp: Date;
      duration: string;
      content?: string;
    }
  | {
      type: MessageType.COMPRESSION;
      compression: CompressionProps;
      timestamp: Date;
    };

export interface ConsoleMessageItem {
  type: 'log' | 'warn' | 'error' | 'debug' | 'info';
  content: string;
  count: number;
}

/**
 * Result type for a slash command that should immediately result in a prompt
 * being submitted to the Gemini model.
 */
export interface SubmitPromptResult {
  type: 'submit_prompt';
  content: PartListUnion;
}

/**
 * Defines the result of the slash command processor for its consumer (useGeminiStream).
 */
export type SlashCommandProcessorResult =
  | {
      type: 'schedule_tool';
      toolName: string;
      toolArgs: Record<string, unknown>;
      postSubmitPrompt?: PartListUnion;
    }
  | {
      type: 'handled'; // Indicates the command was processed and no further action is needed.
    }
  | SubmitPromptResult;

export interface ConfirmationRequest {
  prompt: ReactNode;
  onConfirm: (confirm: boolean) => void;
}

export interface LoopDetectionConfirmationRequest {
  onComplete: (result: { userSelection: 'disable' | 'keep' }) => void;
}

export interface PermissionConfirmationRequest {
  files: string[];
  onComplete: (result: { allowed: boolean }) => void;
}

export interface ActiveHook {
  name: string;
  eventName: string;
  source?: string;
  index?: number;
  total?: number;
}
