import React from 'react';
import { Box, Text } from 'ink';
import Spinner from 'ink-spinner';
import type { Message, ToolCall } from '../hooks/use-socket.js';

export interface MessageListProps {
  messages: Message[];
  isStreaming: boolean;
  currentStreamText: string;
  currentThinkingText: string;
  activeToolCalls: ToolCall[];
  scrollOffset?: number;
  viewportSize?: number;
  isScrolledUp?: boolean;
  highlightedMessageIndices?: Set<number>;
  currentHighlightIndex?: number;
}

function formatTime(date: Date): string {
  return date.toLocaleTimeString('en-US', {
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  });
}

function SystemMessageBubble({ msg }: { msg: Message }) {
  return (
    <Box flexDirection="row" marginBottom={1} marginLeft={2}>
      <Text dimColor>{'⚙ '}</Text>
      <Text dimColor wrap="wrap">
        {msg.content}
      </Text>
    </Box>
  );
}

function MessageBubble({
  msg,
  highlight,
}: {
  msg: Message;
  highlight?: 'match' | 'current' | undefined;
}) {
  if (msg.role === 'system') {
    return <SystemMessageBubble msg={msg} />;
  }

  const isUser = msg.role === 'user';
  const prefix = isUser ? '❯' : '◆';
  const color = isUser ? 'green' : 'cyan';

  const borderIndicator =
    highlight === 'current' ? (
      <Text color="yellowBright" bold>
        ▌{' '}
      </Text>
    ) : highlight === 'match' ? (
      <Text color="yellow">▌ </Text>
    ) : null;

  return (
    <Box flexDirection="row" marginBottom={1}>
      {borderIndicator}
      <Box flexDirection="column">
        <Box>
          <Text bold color={color}>
            {prefix}{' '}
          </Text>
          <Text bold color={color}>
            {isUser ? 'you' : 'assistant'}
          </Text>
          <Text dimColor> {formatTime(msg.timestamp)}</Text>
        </Box>
        <Box marginLeft={2}>
          <Text wrap="wrap">{msg.content}</Text>
        </Box>
      </Box>
    </Box>
  );
}

function ToolCallIndicator({ toolCall }: { toolCall: ToolCall }) {
  const icon = toolCall.status === 'running' ? null : toolCall.status === 'success' ? '✓' : '✗';
  const color =
    toolCall.status === 'running' ? 'yellow' : toolCall.status === 'success' ? 'green' : 'red';

  return (
    <Box marginLeft={2}>
      {toolCall.status === 'running' ? (
        <Text color="yellow">
          <Spinner type="dots" />
        </Text>
      ) : (
        <Text color={color}>{icon}</Text>
      )}
      <Text dimColor> tool: </Text>
      <Text color={color}>{toolCall.toolName}</Text>
    </Box>
  );
}

export function MessageList({
  messages,
  isStreaming,
  currentStreamText,
  currentThinkingText,
  activeToolCalls,
  scrollOffset,
  viewportSize,
  isScrolledUp,
  highlightedMessageIndices,
  currentHighlightIndex,
}: MessageListProps) {
  const useSlicing = scrollOffset != null && viewportSize != null;
  const visibleMessages = useSlicing
    ? messages.slice(scrollOffset, scrollOffset + viewportSize)
    : messages;
  const hiddenAbove = useSlicing ? scrollOffset : 0;

  return (
    <Box flexDirection="column" flexGrow={1} paddingX={1}>
      {isScrolledUp && hiddenAbove > 0 && (
        <Box justifyContent="center">
          <Text dimColor>↑ {hiddenAbove} more messages ↑</Text>
        </Box>
      )}

      {messages.length === 0 && !isStreaming && (
        <Box justifyContent="center" marginY={1}>
          <Text dimColor>No messages yet. Type below to start a conversation.</Text>
        </Box>
      )}

      {visibleMessages.map((msg, i) => {
        const globalIndex = hiddenAbove + i;
        const highlight =
          globalIndex === currentHighlightIndex
            ? ('current' as const)
            : highlightedMessageIndices?.has(globalIndex)
              ? ('match' as const)
              : undefined;
        return <MessageBubble key={globalIndex} msg={msg} highlight={highlight} />;
      })}

      {/* Active thinking */}
      {isStreaming && currentThinkingText && (
        <Box flexDirection="column" marginBottom={1} marginLeft={2}>
          <Text dimColor italic>
            💭 {currentThinkingText}
          </Text>
        </Box>
      )}

      {/* Active tool calls */}
      {activeToolCalls.length > 0 && (
        <Box flexDirection="column" marginBottom={1}>
          {activeToolCalls.map((tc) => (
            <ToolCallIndicator key={tc.toolCallId} toolCall={tc} />
          ))}
        </Box>
      )}

      {/* Streaming response */}
      {isStreaming && currentStreamText && (
        <Box flexDirection="column" marginBottom={1}>
          <Box>
            <Text bold color="cyan">
              ◆{' '}
            </Text>
            <Text bold color="cyan">
              assistant
            </Text>
          </Box>
          <Box marginLeft={2}>
            <Text wrap="wrap">{currentStreamText}</Text>
          </Box>
        </Box>
      )}

      {/* Waiting spinner */}
      {isStreaming && !currentStreamText && activeToolCalls.length === 0 && (
        <Box marginLeft={2}>
          <Text color="cyan">
            <Spinner type="dots" />
          </Text>
          <Text dimColor> thinking…</Text>
        </Box>
      )}
    </Box>
  );
}
