import { HIDDEN_TOOLS } from '$frontend/components/chat/tools/registry';
import type { FrontendMessage } from '$frontend/stores/core/sessions.svelte';
import type {
  AssistantContentBlock,
  UserContentBlock,
  ToolUseBlock,
  ToolResult,
  KnownToolName,
} from '$shared/types/unified';

// Message types that represent actual conversation content and should be rendered.
const RENDERABLE_MESSAGE_TYPES = new Set(['assistant', 'user', 'reasoning', 'stream_event']);

// Check if this is a compact boundary message
export function isCompactBoundaryMessage(message: FrontendMessage): boolean {
  return message.type === 'compact_boundary';
}

// Check if this is a synthetic user message (generated by system after compaction)
export function isSyntheticUserMessage(message: FrontendMessage): boolean {
  return message.type === 'user' && 'synthetic' in message && (message as any).synthetic === true;
}

// Check if this is a sub-agent user message (prompt sent to a sub-agent)
export function isSubAgentUserMessage(message: FrontendMessage): boolean {
  return message.type === 'user' &&
    'parent' in message &&
    (message as any).parent.toolUseId !== null;
}

// Check if a message should be filtered out
export function shouldFilterMessage(message: FrontendMessage): boolean {
  // Allow compact boundary messages (displayed as separator in chat)
  if (isCompactBoundaryMessage(message)) {
    return false;
  }

  // Whitelist approach: only render conversation content types.
  if (!RENDERABLE_MESSAGE_TYPES.has(message.type)) {
    return true;
  }

  // Filter out streaming messages whose text is empty or whitespace-only
  // (engines sometimes emit lone "\n" deltas that produce blank bubbles)
  if (message.type === 'stream_event') {
    if (!message.text?.trim()) {
      return true;
    }
  }

  // Filter out reasoning messages whose text is empty or whitespace-only
  if (message.type === 'reasoning' && 'text' in message) {
    if (!(message as any).text?.trim()) {
      return true;
    }
  }

  // Filter out assistant messages with no visible content
  if (message.type === 'assistant' && 'content' in message) {
    const content = message.content;

    if (!content || content.length === 0) {
      return true;
    }

    // Check if there's any meaningful visible content
    const hasNonEmptyText = content.some(
      (item) => item.type === 'text' && 'text' in item && (item as any).text?.trim().length > 0
    );
    const hasToolUse = content.some((item) => item.type === 'tool_use');
    if (!hasNonEmptyText && !hasToolUse) {
      return true;
    }
  }

  return false;
}

// Extract tool uses from assistant content
export function extractToolUses(content: AssistantContentBlock[]): ToolUseBlock[] {
  return content.filter((item): item is ToolUseBlock => item.type === 'tool_use');
}

// Extract tool results from user content
export function extractToolResults(content: UserContentBlock[]): ToolResult[] {
  return content.filter((item): item is ToolResult => item.type === 'tool_result');
}

// Check if a tool should be hidden from the chat stream
export function shouldHideTool(toolName: string): boolean {
  return HIDDEN_TOOLS.has(toolName as KnownToolName);
}
