// v1.14.x-html-artifact-panes: full-height HTML artifact viewer. Renders the
// model's HTML inside a sandboxed iframe — no allow-same-origin, srcdoc only
// (no separate URL), CSP injected by the backend writer. JS runs inside the
// iframe (interactive controls work) but fetch / WS / tracking pixels are
// blocked by connect-src 'none' on the CSP. NO Copy button per the spec.
//
// Pane state is a reference only (chat_id + message_id + title); the iframe
// payload is fetched on mount from
// GET /api/chats/:chat_id/messages/:msg_id/html_artifact so that
// sessions.workspace_panes jsonb stays small and message_parts.payload is the
// single source of truth.
import { useEffect, useState } from 'react';
import { api } from '@/api/client';
import type { HtmlArtifactState } from '@/api/types';
import { ArtifactPaneHeader } from './ArtifactPaneHeader';
import { useArtifactDownload } from '@/hooks/useArtifactDownload';

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

export function HtmlArtifactPane({ chatId, state, onClose }: Props) {
  const [htmlContent, setHtmlContent] = useState<string | null>(null);
  const [loadError, setLoadError] = useState<string | null>(null);
  const { downloading, download } = useArtifactDownload(chatId, state.message_id, 'html');

  useEffect(() => {
    let cancelled = false;
    setHtmlContent(null);
    setLoadError(null);
    void (async () => {
      try {
        const payload = await api.messages.getHtmlArtifact(chatId, state.message_id);
        if (cancelled) return;
        setHtmlContent(payload.html_content);
      } catch (err) {
        if (cancelled) return;
        setLoadError(err instanceof Error ? err.message : 'failed to load HTML artifact');
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [chatId, state.message_id]);

  return (
    <div className="flex flex-col h-full min-h-0">
      <ArtifactPaneHeader
        title={state.title}
        defaultTitle="HTML artifact"
        onDownload={() => void download()}
        downloadDisabled={downloading || htmlContent === null}
        onClose={onClose}
      />
      <div className="flex-1 min-h-0 overflow-hidden bg-background">
        {loadError ? (
          <div className="p-4 text-sm text-destructive">Failed to load: {loadError}</div>
        ) : htmlContent === null ? (
          <div className="p-4 text-sm text-muted-foreground">Loading HTML artifact…</div>
        ) : (
          <iframe
            // Sandbox attributes are non-negotiable per the v1.14.x spec S5:
            // no allow-same-origin → opaque origin → can't reach parent cookies
            // or DOM. srcdoc (not src) means no URL exists to leak. JS runs
            // (allow-scripts) but connect-src 'none' on the CSP inside the
            // payload blocks fetch / WS / pixels.
            srcDoc={htmlContent}
            sandbox="allow-scripts allow-clipboard-write allow-downloads"
            className="w-full h-full border-0"
            title={state.title || 'HTML artifact'}
          />
        )}
      </div>
    </div>
  );
}
