"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import type { Message } from "@/hooks/useChat";

interface MessageListProps {
  messages: Message[];
  isLoading: boolean;
  isStreaming?: boolean;
  streamingMessageId?: string;
  loadingQuip?: string | null;
}

/**
 * Parse thinking content from message.
 * Extracts <thinking>...</thinking> or <think>...</think> blocks.
 */
function parseThinking(content: string): { thinking: string | null; response: string } {
  const thinkingRegex = /<(?:thinking|think)>([\s\S]*?)<\/(?:thinking|think)>/gi;
  const matches = content.match(thinkingRegex);

  if (!matches) {
    return { thinking: null, response: content };
  }

  let thinking = "";
  for (const match of matches) {
    const innerContent = match.replace(/<\/?(?:thinking|think)>/gi, "");
    thinking += innerContent.trim() + "\n";
  }

  const response = content.replace(thinkingRegex, "").trim();

  const trimmedThinking = thinking.trim();
  return {
    thinking: trimmedThinking.length > 0 ? trimmedThinking : null,
    response,
  };
}

export function MessageList({
  messages,
  isLoading,
  isStreaming = false,
  streamingMessageId,
  loadingQuip,
}: MessageListProps): React.JSX.Element {
  const bottomRef = useRef<HTMLDivElement>(null);

  // Auto-scroll to bottom when messages change or streaming tokens arrive
  useEffect(() => {
    if (isStreaming || isLoading) {
      bottomRef.current?.scrollIntoView({ behavior: "smooth" });
    }
  }, [messages, isStreaming, isLoading]);

  return (
    <div className="space-y-6" role="log" aria-label="Chat messages">
      {messages.map((message) => (
        <MessageBubble
          key={message.id}
          message={message}
          isStreaming={isStreaming && message.id === streamingMessageId}
        />
      ))}

      {isLoading && !isStreaming && (
        <LoadingIndicator {...(loadingQuip != null && { quip: loadingQuip })} />
      )}
      <div ref={bottomRef} />
    </div>
  );
}

interface MessageBubbleProps {
  message: Message;
  isStreaming?: boolean;
}

function MessageBubble({ message, isStreaming = false }: MessageBubbleProps): React.JSX.Element {
  const isUser = message.role === "user";
  const [copied, setCopied] = useState(false);
  const [thinkingExpanded, setThinkingExpanded] = useState(false);

  const { thinking, response } = message.thinking
    ? { thinking: message.thinking, response: message.content }
    : parseThinking(message.content);

  const handleCopy = useCallback(async () => {
    try {
      await navigator.clipboard.writeText(response);
      setCopied(true);
      setTimeout(() => {
        setCopied(false);
      }, 2000);
    } catch (err) {
      void err;
    }
  }, [response]);

  return (
    <div
      className={`group flex gap-4 message-animate ${isUser ? "flex-row-reverse" : ""}`}
      role="article"
      aria-label={`${isUser ? "Your" : "AI Assistant"} message`}
    >
      {/* Avatar */}
      <div
        className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg text-xs font-semibold"
        style={{
          backgroundColor: isUser ? "rgb(var(--surface-2))" : "rgb(var(--accent-primary))",
          color: isUser ? "rgb(var(--text-secondary))" : "white",
        }}
        aria-hidden="true"
      >
        {isUser ? "You" : "AI"}
      </div>

      {/* Message Content */}
      <div className={`flex max-w-[85%] flex-col gap-1.5 ${isUser ? "items-end" : "items-start"}`}>
        {/* Message Header */}
        <div
          className={`flex items-center gap-2 text-xs ${isUser ? "flex-row-reverse" : ""}`}
          style={{ color: "rgb(var(--text-muted))" }}
        >
          <span className="font-medium" style={{ color: "rgb(var(--text-secondary))" }}>
            {isUser ? "You" : "AI Assistant"}
          </span>
          {/* Streaming indicator in header */}
          {!isUser && isStreaming && (
            <span
              className="px-1.5 py-0.5 rounded text-[10px] font-medium"
              style={{
                backgroundColor: "rgb(var(--accent-primary) / 0.15)",
                color: "rgb(var(--accent-primary))",
              }}
              aria-label="Streaming"
            >
              streaming
            </span>
          )}
          {/* Model indicator for assistant messages */}
          {!isUser && message.model && !isStreaming && (
            <span
              className="px-1.5 py-0.5 rounded text-[10px] font-medium"
              style={{
                backgroundColor: "rgb(var(--surface-2))",
                color: "rgb(var(--text-tertiary))",
              }}
              title={message.provider ? `Provider: ${message.provider}` : undefined}
            >
              {message.model}
            </span>
          )}
          {/* Token usage indicator for assistant messages */}
          {!isUser && message.totalTokens !== undefined && message.totalTokens > 0 && (
            <span
              className="px-1.5 py-0.5 rounded text-[10px] font-medium"
              style={{
                backgroundColor: "rgb(var(--surface-2))",
                color: "rgb(var(--text-muted))",
              }}
              title={`Prompt: ${message.promptTokens?.toLocaleString() ?? "0"} tokens, Completion: ${message.completionTokens?.toLocaleString() ?? "0"} tokens`}
            >
              {formatTokenCount(message.totalTokens)} tokens
            </span>
          )}
          <span aria-label={`Sent at ${formatTime(message.createdAt)}`}>
            {formatTime(message.createdAt)}
          </span>
        </div>

        {/* Thinking Section - Collapsible */}
        {thinking && !isUser && (
          <div
            className="rounded-lg overflow-hidden"
            style={{
              backgroundColor: "rgb(var(--surface-1))",
              border: "1px solid rgb(var(--border-default))",
            }}
          >
            <button
              onClick={() => {
                setThinkingExpanded(!thinkingExpanded);
              }}
              className="w-full flex items-center gap-2 px-3 py-2 text-xs font-medium hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
              style={{ color: "rgb(var(--text-secondary))" }}
              aria-expanded={thinkingExpanded}
            >
              <svg
                className={`h-3.5 w-3.5 transition-transform duration-200 ${thinkingExpanded ? "rotate-90" : ""}`}
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                strokeWidth={2}
              >
                <path d="m9 18 6-6-6-6" />
              </svg>
              <svg
                className="h-3.5 w-3.5"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                strokeWidth={2}
              >
                <path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
              </svg>
              <span>Thinking</span>
              <span className="ml-auto text-xs" style={{ color: "rgb(var(--text-muted))" }}>
                {thinkingExpanded ? "Hide" : "Show"} reasoning
              </span>
            </button>
            {thinkingExpanded && (
              <div
                className="px-3 pb-3 text-xs leading-relaxed whitespace-pre-wrap font-mono"
                style={{
                  color: "rgb(var(--text-secondary))",
                  borderTop: "1px solid rgb(var(--border-default))",
                }}
              >
                {thinking}
              </div>
            )}
          </div>
        )}

        {/* Message Body */}
        <div
          className="relative rounded-lg px-4 py-3"
          style={{
            backgroundColor: isUser ? "rgb(var(--accent-primary))" : "rgb(var(--surface-0))",
            color: isUser ? "white" : "rgb(var(--text-primary))",
            border: isUser ? "none" : "1px solid rgb(var(--border-default))",
          }}
        >
          <p className="whitespace-pre-wrap text-sm leading-relaxed">
            {response}
            {/* Blinking cursor during streaming */}
            {isStreaming && !isUser && (
              <span
                className="streaming-cursor inline-block ml-0.5 align-middle"
                aria-hidden="true"
              />
            )}
          </p>

          {/* Copy Button - hidden while streaming */}
          {!isStreaming && (
            <button
              onClick={handleCopy}
              className="absolute -right-2 -top-2 rounded-md border p-1.5 opacity-0 transition-all group-hover:opacity-100 focus:opacity-100"
              style={{
                backgroundColor: "rgb(var(--surface-0))",
                borderColor: "rgb(var(--border-default))",
                color: copied ? "rgb(var(--semantic-success))" : "rgb(var(--text-muted))",
              }}
              aria-label={copied ? "Copied!" : "Copy message"}
              title={copied ? "Copied!" : "Copy to clipboard"}
            >
              {copied ? (
                <svg
                  className="h-3.5 w-3.5"
                  fill="none"
                  viewBox="0 0 24 24"
                  stroke="currentColor"
                  strokeWidth={2}
                >
                  <polyline points="20 6 9 17 4 12" />
                </svg>
              ) : (
                <svg
                  className="h-3.5 w-3.5"
                  fill="none"
                  viewBox="0 0 24 24"
                  stroke="currentColor"
                  strokeWidth={2}
                >
                  <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
                  <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
                </svg>
              )}
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

function LoadingIndicator({ quip }: { quip?: string | null }): React.JSX.Element {
  return (
    <div className="flex gap-4 message-animate" role="status" aria-label="AI is typing">
      {/* Avatar */}
      <div
        className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg text-xs font-semibold"
        style={{ backgroundColor: "rgb(var(--accent-primary))" }}
        aria-hidden="true"
      >
        <span className="text-white">AI</span>
      </div>

      {/* Loading Content */}
      <div className="flex flex-col gap-1.5">
        <div
          className="flex items-center gap-2 text-xs"
          style={{ color: "rgb(var(--text-muted))" }}
        >
          <span className="font-medium" style={{ color: "rgb(var(--text-secondary))" }}>
            AI Assistant
          </span>
          <span>thinking...</span>
        </div>

        <div
          className="rounded-lg border px-4 py-3"
          style={{
            backgroundColor: "rgb(var(--surface-0))",
            borderColor: "rgb(var(--border-default))",
          }}
        >
          <div className="flex items-center gap-2">
            <div className="flex items-center gap-1.5">
              <span
                className="h-1.5 w-1.5 rounded-full animate-bounce"
                style={{
                  backgroundColor: "rgb(var(--accent-primary))",
                  animationDelay: "0ms",
                }}
              />
              <span
                className="h-1.5 w-1.5 rounded-full animate-bounce"
                style={{
                  backgroundColor: "rgb(var(--accent-primary))",
                  animationDelay: "150ms",
                }}
              />
              <span
                className="h-1.5 w-1.5 rounded-full animate-bounce"
                style={{
                  backgroundColor: "rgb(var(--accent-primary))",
                  animationDelay: "300ms",
                }}
              />
            </div>
            {quip && (
              <span
                className="text-sm italic animate-fade-in"
                style={{ color: "rgb(var(--text-muted))" }}
              >
                {quip}
              </span>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

export function formatTime(isoString: string): string {
  try {
    const date = new Date(isoString);
    if (isNaN(date.getTime())) {
      return "Invalid date";
    }
    return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
  } catch {
    return "Invalid date";
  }
}

function formatTokenCount(tokens: number): string {
  if (tokens >= 1000000) {
    return `${(tokens / 1000000).toFixed(1)}M`;
  } else if (tokens >= 1000) {
    return `${(tokens / 1000).toFixed(1)}K`;
  }
  return tokens.toString();
}
