/**
 * MessageBubble — renders a single user or assistant message in the chat thread.
 *
 * - User bubbles: violet gradient background, white text
 * - Assistant bubbles: white card, rounded, with shadow; Markdown content;
 *   citation chips, save/export buttons, and metadata bar below completed messages
 *
 * Requirements: 4.4, 4.7, 4.8, 5.1, 7.1, 7.6, 11.2, 12.3, 12.4
 */

import { useState, useEffect, useRef } from "react";
import ReactMarkdown from "react-markdown";
import { remarkPlugins, rehypePlugins, components } from "../lib/markdown";
import { CitationChips } from "./CitationChips";
import type { Message, QueryResult } from "../types";

// Messages shown while waiting for the pipeline to return tokens.
// The last entry appears once the first token arrives.
const RETRIEVAL_MESSAGES = [
  "Looking at the legislation",
  "Reviewing relevant regulations",
  "Assessing requirements",
  "Scanning specific guidelines",
  "Understanding policy recommendations",
];
const GENERATING_MESSAGE = "Generating tailored response";
const CYCLE_INTERVAL_MS = 2500;

export interface MessageBubbleProps {
  message: Message;
  index: number;
  conversationId: string;
  result?: QueryResult;
  isStreaming?: boolean;
  isSaved?: boolean;
  onSave?: (index: number) => void;
  onExport?: (index: number) => void;
}

/**
 * Renders a single chat message bubble.
 *
 * User messages use a violet gradient background with white text.
 * Assistant messages use a full-width white card with rounded corners and shadow,
 * with Markdown rendering, citation chips, a collapsible detail panel,
 * and a metadata bar with timing info + Save Response pill button.
 */
export function MessageBubble({
  message,
  index,
  conversationId: _conversationId,
  result,
  isStreaming = false,
  isSaved = false,
  onSave,
  onExport,
}: MessageBubbleProps) {
  const isUser = message.role === "user";
  const isCompleted = !isStreaming && message.role === "assistant";
  const hasContent = message.content.trim().length > 0;

  // Cycle through retrieval messages while waiting for first tokens
  const [msgIndex, setMsgIndex] = useState(0);
  const intervalRef = useRef<number | null>(null);

  useEffect(() => {
    if (isStreaming && !hasContent) {
      // Start cycling
      intervalRef.current = setInterval(() => {
        setMsgIndex((i) => (i + 1) % RETRIEVAL_MESSAGES.length);
      }, CYCLE_INTERVAL_MS);
    } else {
      // Stop cycling when tokens arrive or streaming ends
      if (intervalRef.current !== null) {
        clearInterval(intervalRef.current);
        intervalRef.current = null;
      }
    }
    return () => {
      if (intervalRef.current !== null) clearInterval(intervalRef.current);
    };
  }, [isStreaming, hasContent]);

  if (isUser) {
    return (
      <div className="flex justify-end mb-4">
        <div
          className="max-w-[80%] px-4 py-3 text-white"
          style={{
            background: "linear-gradient(135deg, #542FE8 0%, #1E3798 100%)",
            borderRadius: "14px",
            fontSize: "0.95rem",
            fontWeight: 400,
            lineHeight: 1.55,
          }}
        >
          {message.content}
        </div>
      </div>
    );
  }

  return (
    <div className="mb-6">
      <div className="w-full">
          {/* White card */}
          <div
            className="px-6 py-5"
            style={{
              backgroundColor: "#FFFFFF",
              borderRadius: "16px",
              boxShadow: "0 4px 24px rgba(0,0,0,0.12)",
              minHeight: isStreaming ? "80px" : undefined,
            }}
          >
            {/* Retrieval phase — cycling status messages before first token */}
            {isStreaming && !hasContent && (
              <div className="flex items-center gap-2 py-2">
                <span className="text-sm text-gray-400">{RETRIEVAL_MESSAGES[msgIndex]}</span>
                <div className="flex gap-1">
                  <span
                    className="w-2 h-2 rounded-full bg-gray-300"
                    style={{ animation: "pulse 1.4s ease-in-out 0s infinite" }}
                  />
                  <span
                    className="w-2 h-2 rounded-full bg-gray-300"
                    style={{ animation: "pulse 1.4s ease-in-out 0.2s infinite" }}
                  />
                  <span
                    className="w-2 h-2 rounded-full bg-gray-300"
                    style={{ animation: "pulse 1.4s ease-in-out 0.4s infinite" }}
                  />
                </div>
              </div>
            )}

            {/* Generation phase label — shown while tokens are streaming in */}
            {isStreaming && hasContent && (
              <div className="flex items-center gap-2 pb-3">
                <span className="text-xs text-gray-400">{GENERATING_MESSAGE}</span>
                <div className="flex gap-1">
                  <span className="w-1.5 h-1.5 rounded-full bg-gray-300" style={{ animation: "pulse 1.4s ease-in-out 0s infinite" }} />
                  <span className="w-1.5 h-1.5 rounded-full bg-gray-300" style={{ animation: "pulse 1.4s ease-in-out 0.2s infinite" }} />
                  <span className="w-1.5 h-1.5 rounded-full bg-gray-300" style={{ animation: "pulse 1.4s ease-in-out 0.4s infinite" }} />
                </div>
              </div>
            )}

            {/* Markdown-rendered assistant content */}
            {hasContent && (
              <div className="max-w-none" style={{ color: "#1C2942" }}>
                <ReactMarkdown
                  remarkPlugins={remarkPlugins}
                  rehypePlugins={rehypePlugins}
                  components={components}
                >
                  {message.content}
                </ReactMarkdown>
              </div>
            )}

            {/* Citation chips + collapsible detail — only for completed messages */}
            {isCompleted && (
              <div className="mt-4">
                {result && result.citations.length > 0 && (
                  <CitationChips citations={result.citations} />
                )}

                {/* Collapsible "Full citation detail" card */}
                {result && result.citations.length > 0 && (
                  <CitationDetailPanel citations={result.citations} />
                )}
              </div>
            )}
          </div>

          {/* Bottom metadata bar — timing, sections, domains, tokens + Save Response */}
          {isCompleted && result && (
            <div className="flex items-center justify-between mt-3 px-1">
              <MetadataBar result={result} />

              <div className="flex items-center gap-2">
                {onExport && (
                  <button
                    type="button"
                    onClick={() => onExport(index)}
                    className="flex items-center gap-1 text-xs text-gray-400 hover:text-gray-600 transition-colors"
                    title="Download response"
                    aria-label="Download response"
                  >
                    <DownloadIcon />
                  </button>
                )}

                {onSave && (
                  <button
                    type="button"
                    onClick={() => onSave(index)}
                    className="flex items-center gap-1.5 px-4 py-2 rounded-full text-sm font-medium text-white transition-all active:scale-95"
                    style={{
                      backgroundColor: isSaved ? "#3B2498" : "#4A2DB8",
                    }}
                    title={isSaved ? "Response saved" : "Save response"}
                    aria-label={isSaved ? "Response saved" : "Save response"}
                  >
                    <span>{isSaved ? "Saved" : "Save Response"}</span>
                  </button>
                )}
              </div>
            </div>
          )}
        </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Internal sub-components
// ---------------------------------------------------------------------------

/**
 * Collapsible full citation detail panel with chevron and card styling.
 */
function CitationDetailPanel({
  citations,
}: {
  citations: QueryResult["citations"];
}) {
  const [open, setOpen] = useState(false);

  return (
    <div className="mt-3">
      <button
        type="button"
        onClick={() => setOpen((prev) => !prev)}
        className="w-full flex items-center gap-2 px-4 py-3 text-sm text-gray-700 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
        aria-expanded={open}
      >
        <ChevronIcon open={open} />
        <span>Full citation detail</span>
      </button>

      {open && (
        <div className="mt-2 space-y-2">
          {citations.map((c) => (
            <div
              key={c.index}
              className="text-xs text-gray-600 border border-gray-200 rounded-md p-3 bg-gray-50"
            >
              <div className="flex items-center gap-2">
                <span className="font-semibold text-gray-700">[{c.index}]</span>
                <span className="font-medium">{c.domain}</span>
              </div>
              <div className="mt-1 text-gray-800">{c.title}</div>
              {c.source_url && (
                <div className="mt-1 truncate">
                  <a
                    href={c.source_url}
                    target="_blank"
                    rel="noopener"
                    className="text-blue-600 hover:underline"
                  >
                    {c.source_url}
                  </a>
                </div>
              )}
              {c.line_num !== undefined && (
                <div className="mt-1 text-gray-500">Line {c.line_num}</div>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/**
 * Metadata bar showing timing · sections · domains · tokens.
 */
function MetadataBar({ result }: { result: QueryResult }) {
  const parts: string[] = [];

  if (result.timing?.total !== undefined) {
    parts.push(`${result.timing.total.toFixed(0)}s`);
  }

  if (result.sections_retrieved !== undefined && result.sections_retrieved > 0) {
    parts.push(`${result.sections_retrieved} section${result.sections_retrieved > 1 ? "s" : ""}`);
  }

  if (result.domains_searched && result.domains_searched.length > 0) {
    parts.push(
      result.domains_searched
        .map((d) =>
          d
            .replace(/_/g, " ")
            .replace(/\b\w/g, (c) => c.toUpperCase())
        )
        .join(", ")
    );
  }

  if (result.token_usage?.total_tokens) {
    parts.push(`${result.token_usage.total_tokens.toLocaleString()} tokens`);
  }

  if (parts.length === 0) return null;

  return (
    <p className="text-xs text-gray-500 leading-relaxed">
      {parts.join(" · ")}
    </p>
  );
}

// ---------------------------------------------------------------------------
// Icon components
// ---------------------------------------------------------------------------

function ChevronIcon({ open }: { open: boolean }) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      fill="none"
      viewBox="0 0 24 24"
      strokeWidth={2}
      stroke="currentColor"
      className="w-4 h-4 text-gray-400 transition-transform"
      style={{ transform: open ? "rotate(90deg)" : "rotate(0deg)" }}
      aria-hidden="true"
    >
      <path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
    </svg>
  );
}

function DownloadIcon() {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      fill="none"
      viewBox="0 0 24 24"
      strokeWidth={1.5}
      stroke="currentColor"
      className="w-4 h-4"
      aria-hidden="true"
    >
      <path
        strokeLinecap="round"
        strokeLinejoin="round"
        d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3"
      />
    </svg>
  );
}

export default MessageBubble;
