import React, { useEffect, useRef, useState } from 'react';
import {
  isAllowedThumbnailMime,
  THUMBNAIL_MAX_BYTES,
} from '@shade/sdk';
import { useShadeRuntimeTheme } from '../../ShadeRuntimeProvider.js';

export interface ThumbnailPreviewProps {
  /** Bytes from `useThumbnail(streamId)`. */
  bytes: Uint8Array | null;
  /** Declared MIME — must be in the allowlist or the preview is blanked. */
  mime: string | null;
  /** Side length in CSS px (square). Default 48. */
  size?: number;
  className?: string;
  style?: React.CSSProperties;
  /** Override the placeholder shown when no thumbnail is available. */
  placeholder?: React.ReactNode;
}

/**
 * V3.9 — safe thumbnail renderer.
 *
 * Defends against malicious image bytes by:
 *  - refusing to render anything outside `THUMBNAIL_MIME_ALLOWLIST`,
 *  - capping displayed sizes at `THUMBNAIL_MAX_BYTES` (defensive — the
 *    cache already enforces this at write-time, but the prop boundary
 *    is the last chance to catch a caller passing arbitrary bytes),
 *  - rendering through a Blob URL inside an `<img>` so the browser's
 *    own image-decoding sandbox is the rendering trust boundary, and
 *  - revoking the Blob URL on unmount so a long-running app doesn't
 *    leak handles.
 */
export function ThumbnailPreview({
  bytes,
  mime,
  size,
  className,
  style,
  placeholder,
}: ThumbnailPreviewProps): React.ReactElement {
  const theme = useShadeRuntimeTheme();
  const [url, setUrl] = useState<string | null>(null);
  const lastUrlRef = useRef<string | null>(null);

  useEffect(() => {
    if (lastUrlRef.current !== null) {
      URL.revokeObjectURL(lastUrlRef.current);
      lastUrlRef.current = null;
    }
    if (
      bytes === null ||
      mime === null ||
      !isAllowedThumbnailMime(mime) ||
      bytes.byteLength === 0 ||
      bytes.byteLength > THUMBNAIL_MAX_BYTES
    ) {
      setUrl(null);
      return;
    }
    const blob = new Blob([bytes as BlobPart], { type: mime });
    const next = URL.createObjectURL(blob);
    lastUrlRef.current = next;
    setUrl(next);
    return () => {
      if (lastUrlRef.current === next) {
        URL.revokeObjectURL(next);
        lastUrlRef.current = null;
      }
    };
  }, [bytes, mime]);

  const edge = size ?? 48;
  const baseStyle: React.CSSProperties = {
    width: edge,
    height: edge,
    flexShrink: 0,
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    background: theme.bg,
    border: `1px solid ${theme.border}`,
    borderRadius: theme.radius,
    overflow: 'hidden',
    color: theme.textMuted,
    fontSize: 11,
    ...style,
  };

  if (url === null) {
    return (
      <div className={className} style={baseStyle}>
        {placeholder ?? <span aria-hidden>—</span>}
      </div>
    );
  }
  return (
    <div className={className} style={baseStyle}>
      <img
        src={url}
        alt=""
        width={edge}
        height={edge}
        decoding="async"
        loading="lazy"
        referrerPolicy="no-referrer"
        style={{
          width: '100%',
          height: '100%',
          objectFit: 'cover',
          display: 'block',
        }}
      />
    </div>
  );
}
