// v1.14.x-html-artifact-panes: dedicated full-height Markdown viewer used
// when a user clicks "Open in pane" on an assistant message that has NO
// html_artifact part. Header carries Copy (raw source) + Download (server-
// materialised .md under <projectRoot>/.boocode/artifacts/) + close.
//
// Pane state is a reference only (chat_id + message_id + title); the markdown
// body is fetched on mount from GET /api/chats/:chat_id/messages by locating
// the matching message_id. This keeps sessions.workspace_panes jsonb small
// and the assistant message row remains the single source of truth.
import { useEffect, useState } from 'react';
import { toast } from 'sonner';
import { api } from '@/api/client';
import type { MarkdownArtifactState } from '@/api/types';
import { MarkdownRenderer } from './MarkdownRenderer';
import { ArtifactPaneHeader } from './ArtifactPaneHeader';
import { useArtifactDownload } from '@/hooks/useArtifactDownload';

interface Props {
  chatId: string;
  state: MarkdownArtifactState;
  onClose: () => void;
}

export function MarkdownArtifactPane({ chatId, state, onClose }: Props) {
  const [justCopied, setJustCopied] = useState(false);
  const [content, setContent] = useState<string | null>(null);
  const [loadError, setLoadError] = useState<string | null>(null);
  const { downloading, download } = useArtifactDownload(chatId, state.message_id, 'md');

  useEffect(() => {
    let cancelled = false;
    setContent(null);
    setLoadError(null);
    void (async () => {
      try {
        // No single-message GET endpoint exists; the chat-messages list is
        // already cached server-side and the lookup is O(n) over a small
        // window. Cheaper than adding a new route for one call site.
        const messages = await api.chats.messages(chatId);
        if (cancelled) return;
        const msg = messages.find((m) => m.id === state.message_id);
        if (!msg) {
          setLoadError('Message not found');
          return;
        }
        setContent(msg.content ?? '');
      } catch (err) {
        if (cancelled) return;
        setLoadError(err instanceof Error ? err.message : 'failed to load message');
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [chatId, state.message_id]);

  async function copy() {
    if (content === null) return;
    try {
      await navigator.clipboard.writeText(content);
      setJustCopied(true);
      setTimeout(() => setJustCopied(false), 1200);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'copy failed');
    }
  }

  return (
    <div className="flex flex-col h-full min-h-0">
      <ArtifactPaneHeader
        title={state.title}
        defaultTitle="Markdown artifact"
        onDownload={() => void download()}
        downloadDisabled={downloading || content === null}
        onClose={onClose}
        onCopy={() => void copy()}
        justCopied={justCopied}
        copyDisabled={content === null}
      />
      <div className="flex-1 min-h-0 overflow-auto px-4 py-3 text-sm">
        {loadError ? (
          <div className="text-destructive">Failed to load: {loadError}</div>
        ) : content === null ? (
          <div className="text-muted-foreground">Loading…</div>
        ) : (
          <MarkdownRenderer content={content} />
        )}
      </div>
    </div>
  );
}
