// ABOUTME: Live preview component — renders an arbitrary list of text layers over a scene/photo.
// ABOUTME: Handles drag-to-position pointer events and the stacked outer-glow text shadow.

const { TextField, Label, Slider, FontPills, ColorSwatches, DividerPills, Section, Toggle, FONTS, COLORS, DIVIDERS, SceneRenderer, getSceneDef } = window;

function resolveColorValue(colorId, customColor) {
  if (colorId === "custom") return customColor || "#fff8e0";
  return (COLORS.find(c => c.id === colorId) || COLORS[0]).value;
}
function resolveFont(id) {
  return FONTS.find(f => f.id === id) || FONTS[0];
}

// Build a stacked outer-glow text-shadow string. Light text glows with its own
// color outward; dark text falls back to a starlight halo so it stays legible
// on a dark scene. A subtle dark drop shadow is layered for contrast.
function buildGlowShadow(textColorHex, strength, scale = 1) {
  if (!strength || strength <= 0) return "none";
  const s = strength / 100;
  const lum = colorLuminance(textColorHex);
  const halo = lum > 0.55 ? textColorHex : "#fff8e0";
  const r1 = Math.max(2,  4  * scale);
  const r2 = Math.max(4,  10 * scale);
  const r3 = Math.max(8,  22 * scale);
  const r4 = Math.max(14, 44 * scale);
  const dropBlur = Math.max(2, 8 * scale);
  const dropY = Math.max(1, 2 * scale);
  const a1 = Math.min(1, s * 1.0).toFixed(3);
  const a2 = Math.min(1, s * 0.85).toFixed(3);
  const a3 = Math.min(1, s * 0.6).toFixed(3);
  const a4 = Math.min(1, s * 0.4).toFixed(3);
  const haloRgba = (alpha) => hexToRgba(halo, alpha);
  return [
    `0 0 ${r1}px ${haloRgba(a1)}`,
    `0 0 ${r2}px ${haloRgba(a2)}`,
    `0 0 ${r3}px ${haloRgba(a3)}`,
    `0 0 ${r4}px ${haloRgba(a4)}`,
    `0 ${dropY}px ${dropBlur}px rgba(0,0,0,${(s * 0.55).toFixed(3)})`,
  ].join(", ");
}

function hexToRgb(hex) {
  let h = hex.replace('#', '');
  if (h.length === 3) h = h.split('').map(c => c + c).join('');
  const n = parseInt(h, 16);
  return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
}
function hexToRgba(hex, a) {
  const { r, g, b } = hexToRgb(hex);
  return `rgba(${r},${g},${b},${a})`;
}
function colorLuminance(hex) {
  const { r, g, b } = hexToRgb(hex);
  // Rec. 709 luma
  return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
}

function TextLayerView({ layer, scale, customColor, isSelected, isDragging, interactive, onPointerDown }) {
  const font = resolveFont(layer.font);
  const color = resolveColorValue(layer.color, customColor);
  const sizePx = layer.size * scale;
  const glow = buildGlowShadow(color, layer.glow ?? 70, scale);
  const isDivider = layer.kind === "divider";
  const fontFamily = isDivider ? "'Cinzel', serif" : font.family;
  const fontStyle = isDivider ? "normal" : (font.italic ? "italic" : "normal");
  const fontWeight = isDivider ? 500 : font.weight;
  const letterSpacing = isDivider ? "0.5em" : (font.letterSpacing ? `${font.letterSpacing}em` : "normal");

  return (
    <div
      onPointerDown={onPointerDown}
      style={{
        position: "absolute",
        left: `${layer.x * 100}%`,
        top: `${layer.y * 100}%`,
        transform: "translate(-50%, -50%)",
        fontFamily, fontWeight, fontStyle,
        fontSize: sizePx,
        color, lineHeight: 1.05,
        letterSpacing,
        textShadow: glow,
        whiteSpace: "pre",
        textAlign: "center",
        cursor: interactive ? (isDragging ? "grabbing" : "grab") : "default",
        padding: "4px 8px",
        outline: interactive && isSelected ? `1px dashed ${color}` : "none",
        outlineOffset: 2,
        opacity: layer.opacity ?? 1,
      }}
    >
      {layer.text}
    </div>
  );
}

function ScreensaverPreview({ state, width, orient, interactive, selectedLayerId, onSelectLayer, onLayerMove }) {
  const W = orient === "portrait" ? 1264 : 1680;
  const H = orient === "portrait" ? 1680 : 1264;
  const scale = width / W;
  const height = H * scale;

  const containerRef = React.useRef(null);
  const [dragging, setDragging] = React.useState(null);

  const handlePointerDown = (layerId) => (e) => {
    if (!interactive) return;
    e.preventDefault();
    e.stopPropagation();
    onSelectLayer && onSelectLayer(layerId);
    const rect = containerRef.current.getBoundingClientRect();
    setDragging({ id: layerId, rect });
    e.target.setPointerCapture && e.target.setPointerCapture(e.pointerId);
  };
  const handlePointerMove = (e) => {
    if (!dragging) return;
    const { rect, id } = dragging;
    const fx = (e.clientX - rect.left) / rect.width;
    const fy = (e.clientY - rect.top) / rect.height;
    const nx = Math.max(0.02, Math.min(0.98, fx));
    const ny = Math.max(0.02, Math.min(0.98, fy));
    onLayerMove && onLayerMove(id, { x: nx, y: ny });
  };
  const handlePointerUp = () => setDragging(null);

  return (
    <div
      ref={containerRef}
      onPointerMove={handlePointerMove}
      onPointerUp={handlePointerUp}
      onPointerLeave={handlePointerUp}
      onPointerDown={() => onSelectLayer && onSelectLayer(null)}
      style={{
        width, height, position: "relative",
        borderRadius: 10,
        boxShadow: `0 0 0 8px #1a103e, 0 0 0 9px rgba(201,168,232,0.4), 0 30px 60px rgba(0,0,0,0.5), 0 0 90px rgba(201,168,232,0.25)`,
        overflow: "hidden",
        background: "#1a103e",
        userSelect: "none", touchAction: "none",
      }}
    >
      {state.uploadedImage ? (
        <img src={state.uploadedImage} style={{
          position: "absolute", inset: 0, width: "100%", height: "100%",
          objectFit: "cover",
        }} draggable={false} />
      ) : (
        <SceneRenderer sceneId={state.scene} id={`preview-${state.scene}-${orient}`} />
      )}

      {(state.layers || []).map(layer => (
        <TextLayerView
          key={layer.id}
          layer={layer}
          scale={scale}
          customColor={state.customColor}
          isSelected={selectedLayerId === layer.id}
          isDragging={dragging?.id === layer.id}
          interactive={interactive}
          onPointerDown={handlePointerDown(layer.id)}
        />
      ))}
    </div>
  );
}

Object.assign(window, {
  ScreensaverPreview, resolveColorValue, resolveFont,
  buildGlowShadow, hexToRgb, hexToRgba, colorLuminance,
});
