// 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 { Download, X } from 'lucide-react';
import { toast } from 'sonner';
import { api } from '@/api/client';
import type { HtmlArtifactState } from '@/api/types';

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

export function HtmlArtifactPane({ chatId, state, onClose }: Props) {
  const [downloading, setDownloading] = useState(false);
  const [htmlContent, setHtmlContent] = useState<string | null>(null);
  const [loadError, setLoadError] = useState<string | null>(null);

  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]);

  async function download() {
    if (downloading) return;
    setDownloading(true);
    try {
      const { url, path } = await api.messages.downloadArtifact(
        chatId,
        state.message_id,
        'html',
      );
      const a = document.createElement('a');
      a.href = url;
      a.rel = 'noopener';
      a.click();
      toast.success(`Saved to ${path}`);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'download failed');
    } finally {
      setDownloading(false);
    }
  }

  return (
    <div className="flex flex-col h-full min-h-0">
      <div className="flex items-center gap-2 border-b border-border bg-muted/30 px-2 py-1 shrink-0">
        <span className="text-xs text-muted-foreground truncate flex-1" title={state.title}>
          {state.title || 'HTML artifact'}
        </span>
        <button
          type="button"
          onClick={() => void download()}
          disabled={downloading || htmlContent === null}
          className="inline-flex items-center justify-center size-5 rounded text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40 max-md:min-h-[44px] max-md:min-w-[44px]"
          aria-label="Download HTML"
          title="Download"
        >
          <Download size={12} />
        </button>
        <button
          type="button"
          onClick={onClose}
          className="inline-flex items-center justify-center size-5 rounded text-muted-foreground hover:bg-muted hover:text-foreground max-md:min-h-[44px] max-md:min-w-[44px]"
          aria-label="Close artifact pane"
          title="Close"
        >
          <X size={12} />
        </button>
      </div>
      <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>
  );
}
