import React, { useEffect, useRef, memo } from 'react';
import { createRoot } from 'react-dom/client';
import type { Root } from 'react-dom/client';
import LivePreview from './LivePreview';
import { CANVAS_DEFAULTS } from './canvasDefaults';

// ─── Grid constants (same as CanvasPage) ─────────────────────────────────────
const GRID_COLS = 48;
const ROW_HEIGHT = 10;
const MARGIN = 8;
// Reference container width for computing pixel ratio (typical canvas width)
const CANVAS_REF_WIDTH = 1200;
const COL_WIDTH = (CANVAS_REF_WIDTH - MARGIN * (GRID_COLS + 1)) / GRID_COLS;

/** Compute real pixel height for h grid rows */
function gridH(h: number): number {
  return h * ROW_HEIGHT + (h - 1) * MARGIN;
}
/** Compute real pixel width for w grid columns */
function gridW(w: number): number {
  return w * COL_WIDTH + (w - 1) * MARGIN;
}

interface Props {
  componentType: string;
  code?: string;
  width?: number;
}

const ComponentThumbnail: React.FC<Props> = memo(
  ({ componentType, code: codeProp, width = 140 }) => {
    const def = CANVAS_DEFAULTS[componentType];
    const containerRef = useRef<HTMLDivElement>(null);
    const rootRef = useRef<Root | null>(null);
    const slotRef = useRef<HTMLDivElement | null>(null);

    if (!def) return null;

    const layout = def.layout;
    const rawCode = codeProp ?? def.variants[0]?.code ?? def.code ?? '';

    // Thumbnail frame: fixed width, height from real pixel ratio
    const thumbW = width;
    const pxW = gridW(layout.w);
    const pxH = gridH(layout.h);
    const thumbH = thumbW * (pxH / pxW);

    // Virtual canvas: use real pixel dimensions as render size
    const renderW = Math.round(pxW);
    const renderH = Math.round(pxH);
    const scale = thumbW / renderW;

    // Replace existing height in code to match ratio; don't inject if none exists
    const code = replaceExistingHeight(rawCode, renderH);

    useEffect(() => {
      const container = containerRef.current;
      if (!container || !code) return;

      cleanup();

      const slot = document.createElement('div');
      Object.assign(slot.style, {
        position: 'absolute',
        top: '0',
        left: '0',
        width: `${renderW}px`,
        height: `${renderH}px`,
        overflow: 'hidden',
        transform: `scale(${scale})`,
        transformOrigin: 'top left',
        pointerEvents: 'none',
      });

      container.appendChild(slot);
      slotRef.current = slot;

      const root = createRoot(slot);
      rootRef.current = root;
      root.render(<LivePreview code={code} />);

      return cleanup;

      function cleanup() {
        const r = rootRef.current;
        const s = slotRef.current;
        rootRef.current = null;
        slotRef.current = null;
        if (r) {
          setTimeout(() => {
            try {
              r.unmount();
            } catch {
              /* unmount may fail if already unmounted */
            }
          }, 0);
        }
        if (s && s.parentNode) {
          s.parentNode.removeChild(s);
        }
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [code, renderW, renderH, scale]);

    return (
      <div
        ref={containerRef}
        style={{
          width: thumbW,
          height: thumbH,
          overflow: 'hidden',
          position: 'relative',
          flexShrink: 0,
        }}
      />
    );
  },
);

ComponentThumbnail.displayName = 'ComponentThumbnail';
export default ComponentThumbnail;

// ─── Helper ──────────────────────────────────────────────────────────────────

/**
 * If code already contains a height value, replace it with the correct ratio-based height.
 * If no height exists, leave code untouched.
 */
function replaceExistingHeight(code: string, h: number): string {
  if (/height\s*=\s*\{[\s\d]+\}/.test(code)) {
    return code.replace(/height\s*=\s*\{[\s\d]+\}/, `height={${h}}`);
  }
  if (/height\s*:\s*\d+/.test(code)) {
    return code.replace(/height\s*:\s*\d+/, `height: ${h}`);
  }
  return code;
}
