// Reusable Thumbnail preview — composes recipe data into a YouTube-style thumb
const { PALETTES, AVATAR_TONES, EMOTIONS } = window.GT_DATA;

const FacePlaceholder = ({ tone = 0, emotion = "shock", size = 100 }) => {
  const t = AVATAR_TONES[tone % AVATAR_TONES.length];
  // Photo entry can be a plain URL string or { src, pos } to override object-position for off-center faces.
  const entry = (t.photos && t.photos[emotion]) || t.photo;
  const photo = typeof entry === "string" ? entry : entry && entry.src;
  const objectPosition = (entry && typeof entry === "object" && entry.pos) || "center";
  return (
    <div style={{ width: size, height: size, borderRadius: "50%", background: t.bg, position: "relative", overflow: "hidden" }}>
      <div style={{
        position: "absolute", inset: 0, display: "grid", placeItems: "center",
        fontFamily: "var(--font-display)", fontWeight: 800, fontSize: size * 0.5, color: "rgba(255,255,255,0.95)",
        textShadow: "0 4px 0 rgba(0,0,0,0.18)"
      }}>{t.initial}</div>
      {photo && (
        <img
          src={photo}
          alt=""
          onError={(e) => { e.currentTarget.style.display = "none"; }}
          style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", objectPosition }}
          loading="lazy"
        />
      )}
    </div>
  );
};

const Thumbnail = ({ recipe, fontSize = 56, showBadge = false, badge = "VAR 1" }) => {
  const p = PALETTES[recipe.palette % PALETTES.length];
  const tmpl = recipe.template;
  const text = recipe.text || "";
  const hl = recipe.hl || "";
  const text2 = recipe.text2 || "";

  const renderText = (style) => (
    <div className="thumb-text" style={style}>
      {text}{hl && <span className="hl">{hl}</span>}{text2}
    </div>
  );

  return (
    <div className="thumb thumb-stripes thumb-vignette">
      <div className="thumb-bg" style={{ background: p.bg }} />
      {showBadge && <div className="thumb-badge">{badge}</div>}

      {tmpl === "split" && <>
        <div style={{ position: "absolute", left: "4%", bottom: "8%", width: "42%", height: "84%", display: "flex", alignItems: "flex-end" }}>
          <FacePlaceholder tone={recipe.avatar} emotion={recipe.emotion} size={Math.round(fontSize * 4)} />
        </div>
        <div style={{ position: "absolute", right: "5%", top: "12%", width: "52%", textAlign: "right", fontSize }}>
          {renderText({ fontSize: "1em" })}
        </div>
        {recipe.arrow && <div className="thumb-arrow" style={{ left: "44%", top: "36%", fontSize: "1.5em" }}>→</div>}
      </>}

      {tmpl === "centered" && <>
        <div style={{ position: "absolute", left: "50%", top: "50%", transform: "translate(-50%, -50%)" }}>
          <FacePlaceholder tone={recipe.avatar} emotion={recipe.emotion} size={Math.round(fontSize * 4.5)} />
        </div>
        <div style={{ position: "absolute", left: "5%", right: "5%", top: "8%", textAlign: "center", fontSize }}>
          {renderText({ fontSize: "1em" })}
        </div>
      </>}

      {tmpl === "bottom" && <>
        <div style={{ position: "absolute", right: "4%", top: "0%", width: "55%", height: "100%", display: "flex", alignItems: "flex-end", justifyContent: "center" }}>
          <FacePlaceholder tone={recipe.avatar} emotion={recipe.emotion} size={Math.round(fontSize * 5)} />
        </div>
        <div style={{ position: "absolute", left: "4%", right: "4%", bottom: "6%", fontSize: fontSize * 1.1 }}>
          {renderText({ fontSize: "1em", lineHeight: 0.95 })}
        </div>
      </>}

      {tmpl === "arrow" && <>
        <div style={{ position: "absolute", left: "5%", bottom: "8%", width: "46%", height: "84%", display: "flex", alignItems: "flex-end" }}>
          <FacePlaceholder tone={recipe.avatar} emotion={recipe.emotion} size={Math.round(fontSize * 4)} />
        </div>
        <div className="thumb-arrow" style={{ left: "44%", top: "30%", fontSize: fontSize * 2.4 }}>→</div>
        <div style={{ position: "absolute", right: "5%", top: "20%", width: "44%", textAlign: "right", fontSize }}>
          {renderText({ fontSize: "1em" })}
        </div>
      </>}

      {tmpl === "number" && <>
        <div style={{ position: "absolute", left: "4%", top: "50%", transform: "translateY(-50%)", fontFamily: "var(--font-display)", fontWeight: 800, fontSize: fontSize * 4, color: "var(--accent)", lineHeight: 1, textShadow: "0 8px 0 rgba(0,0,0,0.5)" }}>{recipe.number}</div>
        <div style={{ position: "absolute", right: "4%", bottom: "6%", width: "55%" }}>
          <FacePlaceholder tone={recipe.avatar} emotion={recipe.emotion} size={Math.round(fontSize * 3.4)} />
        </div>
        <div style={{ position: "absolute", right: "4%", top: "10%", left: "44%", textAlign: "right", fontSize: fontSize * 0.85 }}>
          {renderText({ fontSize: "1em" })}
        </div>
      </>}

      {tmpl === "vs" && <>
        <div style={{ position: "absolute", left: "8%", top: "50%", transform: "translateY(-50%)" }}>
          <FacePlaceholder tone={recipe.avatar} emotion={recipe.emotion} size={Math.round(fontSize * 3.6)} />
        </div>
        <div style={{ position: "absolute", right: "8%", top: "50%", transform: "translateY(-50%)" }}>
          <FacePlaceholder tone={(recipe.avatar + 3) % 8} emotion="serious" size={Math.round(fontSize * 3.6)} />
        </div>
        <div style={{ position: "absolute", left: "50%", top: "50%", transform: "translate(-50%, -50%)", fontFamily: "var(--font-display)", fontWeight: 800, fontSize: fontSize * 2.2, color: "#fff", textShadow: "0 6px 0 var(--brand)" }}>VS</div>
      </>}
    </div>
  );
};

// Composed thumbnail preview for REAL Luma-generated thumbnails: image + N
// text overlays (each with its own x/y/align/color) + optional subject layer
// on top. Used by editor (interactive), gallery cards, and result hero.
const DEFAULT_OVERLAY = {
  hl_color: "#FBBF24", behind_subject: false, font_scale: 1,
};
const DEFAULT_TEXT = {
  pre: "", hl: "", post: "",
  x: 6, y: 80, align: "left", hl_color: "#FBBF24", font_scale: 1, behind_subject: false,
};

// Wrap at the canvas edges, not at the anchor's distance from edge. A long
// centered text positioned near a side should still wrap at the side, even if
// that means overflowing the anchor — the user moves the text after editing.
const TEXT_MAX_WIDTH_PCT = 99;

const TextOverlay = ({ text, scale, draggable, selected, onPointerDown, onClick }) => {
  const t = { ...DEFAULT_TEXT, ...(text || {}) };
  const empty = !t.pre && !t.hl && !t.post;
  if (empty) return null;
  const align = t.align || "left";
  const transformX = align === "center" ? "-50%" : align === "right" ? "-100%" : "0";
  return (
    <div
      onPointerDown={onPointerDown}
      onClick={onClick}
      style={{
        position: "absolute",
        left: `${t.x}%`,
        top: `${t.y}%`,
        transform: `translate(${transformX}, -100%)`,
        textAlign: align,
        fontFamily: "'Montserrat', system-ui, sans-serif",
        fontWeight: 900,
        fontSize: `${9 * (t.font_scale || 1) * (scale || 1)}cqw`,
        lineHeight: 1.02,
        color: "#fff",
        textTransform: "uppercase",
        textShadow: "0 0.04em 0.08em rgba(0,0,0,0.35)",
        letterSpacing: "-0.01em",
        cursor: draggable ? "move" : "default",
        touchAction: "none",
        pointerEvents: draggable ? "auto" : "none",
        // Honor explicit \n line breaks the user types with Enter, but never
        // auto-wrap on spaces. Text that overflows the canvas gets clipped
        // by the stage's overflow:hidden; the user adjusts size or hits
        // Enter to break manually.
        whiteSpace: "pre",
        outline: selected ? "2px dashed var(--brand)" : "none",
        outlineOffset: selected ? "4px" : 0,
        borderRadius: 2,
      }}
    >
      {t.pre && <span>{t.pre} </span>}
      {t.hl && <span style={{color: t.hl_color}}>{t.hl}</span>}
      {t.post && <span> {t.post}</span>}
    </div>
  );
};

const DEFAULT_AVATAR_OVERLAY = { x: 70, y: 50, scale: 1 };

const ComposedThumb = ({
  imageUrl, imageUrlFull,
  subjectUrl, subjectUrlFull,
  // Real photo of the user (bg-removed). When present, it's the source of
  // truth for the face — composited on top of the AI scene. Replaces the
  // legacy generated-subject layer for scene_only thumbs.
  avatarSubjectUrl, avatarSubjectUrlFull,
  avatarOverlay,
  texts, overlay,
  selectedTextId,
  onTextPointerDown, onTextClick,
  onAvatarPointerDown,
  draggable = false, scale = 1,
}) => {
  const avO = { ...DEFAULT_AVATAR_OVERLAY, ...(avatarOverlay || {}) };
  const list = Array.isArray(texts) ? texts : [];
  // While editing, lift the selected text above the subject layer so the user
  // can drag it even when it's marked as "behind". On deselect it falls back
  // to its real layer. (Clicks on a behind-text in the canvas don't reach it
  // through the subject anyway — selection happens via the side-panel list.)
  const isLifted = (t) => draggable && selectedTextId === t.id;
  const behindTexts = list.filter((t) => t.behind_subject && !isLifted(t));
  const frontTexts = list.filter((t) => !t.behind_subject || isLifted(t));
  // Choose which subject layer to render: real avatar wins over legacy generated.
  // Real avatar is always rendered (it IS the face). Legacy generated only when
  // some text wants to sit behind it (its old behavior).
  const useAvatarSubject = !!(avatarSubjectUrl || avatarSubjectUrlFull);
  const useLegacySubject = !useAvatarSubject && behindTexts.length > 0 && (subjectUrl || subjectUrlFull);

  const [imgSrc, setImgSrc] = React.useState(imageUrl || null);
  const [imgLoaded, setImgLoaded] = React.useState(false);
  React.useEffect(() => {
    setImgSrc(imageUrl || null);
    setImgLoaded(false);
  }, [imageUrl]);

  const [subSrc, setSubSrc] = React.useState(subjectUrl || null);
  React.useEffect(() => { setSubSrc(subjectUrl || null); }, [subjectUrl]);

  const [avSubSrc, setAvSubSrc] = React.useState(avatarSubjectUrl || null);
  React.useEffect(() => { setAvSubSrc(avatarSubjectUrl || null); }, [avatarSubjectUrl]);

  const onMainError = () => {
    if (imageUrlFull && imgSrc !== imageUrlFull) setImgSrc(imageUrlFull);
  };
  const onSubError = () => {
    if (subjectUrlFull && subSrc !== subjectUrlFull) setSubSrc(subjectUrlFull);
  };
  const onAvSubError = () => {
    if (avatarSubjectUrlFull && avSubSrc !== avatarSubjectUrlFull) setAvSubSrc(avatarSubjectUrlFull);
  };

  const renderTextLayer = (t, z) => (
    // Wrapper is pointer-events:none so multiple text layers don't block each
    // other — only the actual text's bounding box catches clicks. Without this
    // the last-rendered wrapper at the same z-index would intercept clicks to
    // every text below it in DOM order, even on full-canvas-empty areas.
    <div key={t.id} style={{
      position: "absolute", inset: 0,
      opacity: imgLoaded ? 1 : 0,
      transition: "opacity 0.28s ease-out",
      pointerEvents: "none",
      zIndex: z,
    }}>
      <TextOverlay
        text={t}
        scale={scale}
        draggable={draggable}
        selected={draggable && selectedTextId === t.id}
        onPointerDown={onTextPointerDown ? (e) => onTextPointerDown(e, t.id) : undefined}
        onClick={onTextClick ? (e) => { e.stopPropagation(); onTextClick(t.id); } : undefined}
      />
    </div>
  );

  // Overlays render once the image is ready OR if there's no image yet (the
  // editor is opened during a pending generation — user can still compose text).
  const showOverlays = !imageUrl || imgLoaded;
  const showSkeleton = !imageUrl || !imgLoaded;

  return (
    <div style={{
      position: "absolute", inset: 0,
      containerType: "inline-size",
      userSelect: "none",
      overflow: "hidden",
    }}>
      {showSkeleton && (
        <div className="thumb-skeleton" style={{position: "absolute", inset: 0}} />
      )}
      {imgSrc && (
        <img
          src={imgSrc}
          alt=""
          crossOrigin="anonymous"
          onLoad={() => setImgLoaded(true)}
          onError={onMainError}
          style={{
            position: "absolute", inset: 0,
            width: "100%", height: "100%", objectFit: "cover",
            opacity: imgLoaded ? 1 : 0,
            transition: "opacity 0.28s ease-out",
          }}
        />
      )}
      {/* Layer order: bg → behind texts → subject cutout → front texts. */}
      {showOverlays && behindTexts.map((t) => renderTextLayer(t, 1))}
      {useAvatarSubject && imgLoaded && avSubSrc && (
        <img src={avSubSrc} alt="" aria-hidden crossOrigin="anonymous"
             onError={onAvSubError}
             onPointerDown={draggable && onAvatarPointerDown ? onAvatarPointerDown : undefined}
             style={{
               // Real user photo: x/y are the CENTER position in % of canvas;
               // scale is height multiplier (1 = canvas height). translate
               // -50%/-50% anchors by the center so dragging feels natural.
               position: "absolute",
               left: `${avO.x}%`,
               top: `${avO.y}%`,
               transform: "translate(-50%, -50%)",
               height: `${avO.scale * 100}%`,
               width: "auto",
               objectFit: "contain",
               pointerEvents: draggable ? "auto" : "none",
               cursor: draggable ? "move" : "default",
               touchAction: "none",
               zIndex: 2,
             }} />
      )}
      {useLegacySubject && imgLoaded && subSrc && (
        <img src={subSrc} alt="" aria-hidden crossOrigin="anonymous"
             onError={onSubError}
             style={{
               position: "absolute", inset: 0,
               width: "100%", height: "100%", objectFit: "cover",
               pointerEvents: "none",
               zIndex: 2,
             }} />
      )}
      {showOverlays && frontTexts.map((t) => renderTextLayer(t, 3))}
    </div>
  );
};

// Fallback mock cards if the user hasn't filled web/src/yt-mock.jsx yet.
const YT_MOCK_FALLBACK = [
  { title: "Eu testei TODOS os fones de R$50 do AliExpress", channel: "Tech Manso", views: "1.2M", time: "2 dias", tone: "#3B4252" },
  { title: "POR QUE NINGUÉM FALA SOBRE ISSO?", channel: "Deep Dive BR", views: "847K", time: "1 semana", tone: "#5E2750" },
  { title: "Setup MINIMALISTA pra programador iniciante", channel: "Code Brasil", views: "412K", time: "3 dias", tone: "#1F2937" },
  { title: "Reagindo ao novo trailer (não acreditei)", channel: "Cine Cult", views: "2.1M", time: "5 horas", tone: "#7C2D12" },
  { title: "Como ganhei R$10K em 30 dias (passo a passo)", channel: "Money Lab", views: "638K", time: "1 dia", tone: "#064E3B" },
  { title: "O CASO QUE NINGUÉM EXPLICOU", channel: "História Real", views: "3.4M", time: "2 semanas", tone: "#1E3A8A" },
  { title: "Comprei o iPhone mais BARATO do BRASIL", channel: "Gadget BR", views: "892K", time: "4 dias", tone: "#831843" },
  { title: "Estudo 12 horas/dia (rotina pesada)", channel: "Foco Total", views: "256K", time: "1 dia", tone: "#312E81" },
];

// Color hash so each mocked channel circle has its own consistent color.
function channelColor(name) {
  let h = 0;
  for (let i = 0; i < name.length; i++) h = ((h * 31) + name.charCodeAt(i)) | 0;
  const hue = Math.abs(h) % 360;
  return `hsl(${hue}, 45%, 35%)`;
}

const YouTubePreviewModal = ({ thumbnail, userAvatarUrl, onClose }) => {
  // Lock body scroll while open.
  React.useEffect(() => {
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { document.body.style.overflow = prev; };
  }, []);

  // ESC closes.
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose && onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  const userCard = {
    isUser: true,
    title: thumbnail.title || "Seu vídeo aparece aqui",
    channel: thumbnail.channel || "Seu canal",
    views: "agora",
    time: "agora há pouco",
  };

  // Use user-supplied real thumbnails from web/src/yt-mock.jsx if any, fall
  // back to the gray cards otherwise.
  const realMocks = Array.isArray(window.YT_MOCK_VIDEOS) && window.YT_MOCK_VIDEOS.length > 0
    ? window.YT_MOCK_VIDEOS
    : null;
  const surrounding = realMocks ?? YT_MOCK_FALLBACK;

  // Place the user's card at the second position so it sits next to a "competitor"
  // for honest comparison, but still in the prime above-the-fold area.
  const cards = [...surrounding];
  cards.splice(1, 0, userCard);

  return (
    <div
      onClick={onClose}
      style={{
        position: "fixed", inset: 0,
        background: "rgba(0,0,0,0.85)", backdropFilter: "blur(4px)",
        zIndex: 1000,
        display: "flex", alignItems: "stretch", justifyContent: "center",
        padding: 20, overflow: "auto",
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: "min(1280px, 100%)",
          background: "#0F0F0F", color: "#fff",
          borderRadius: 14, overflow: "hidden",
          fontFamily: "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",
          boxShadow: "0 20px 60px rgba(0,0,0,0.6)",
          position: "relative",
          alignSelf: "flex-start",
        }}
      >
        {/* Fake YouTube top bar */}
        <div style={{
          display: "flex", alignItems: "center", gap: 24,
          padding: "10px 20px", borderBottom: "1px solid #272727",
          background: "#0F0F0F",
        }}>
          <div style={{display: "flex", alignItems: "center", gap: 4, fontWeight: 700}}>
            <span style={{
              background: "#FF0000", color: "#fff",
              width: 26, height: 18, borderRadius: 4,
              display: "inline-flex", alignItems: "center", justifyContent: "center",
              fontSize: 11,
            }}>▶</span>
            <span style={{fontSize: 18, letterSpacing: "-0.04em"}}>YouTube</span>
            <span style={{fontSize: 9, color: "#888", marginTop: -8}}>BR</span>
          </div>
          <div style={{
            flex: 1, maxWidth: 580,
            display: "flex", alignItems: "center",
            border: "1px solid #303030", borderRadius: 999,
            background: "#121212",
            padding: "6px 14px", fontSize: 13, color: "#888",
          }}>
            <span style={{flex: 1}}>Pesquisar</span>
            <span style={{fontSize: 14}}>🔍</span>
          </div>
          <button onClick={onClose} style={{
            marginLeft: "auto", background: "transparent", border: "1px solid #303030",
            color: "#fff", padding: "6px 12px", borderRadius: 999, cursor: "pointer", fontSize: 12,
          }}>
            Fechar preview
          </button>
        </div>

        {/* Filter chips */}
        <div style={{display: "flex", gap: 8, padding: "12px 20px", overflow: "hidden"}}>
          {["Tudo", "Música", "Programação", "Brasil", "Recentes", "Vlogs", "Tecnologia"].map((c, i) => (
            <span key={c} style={{
              padding: "6px 12px", borderRadius: 8,
              background: i === 0 ? "#fff" : "#272727",
              color: i === 0 ? "#000" : "#fff",
              fontSize: 13, fontWeight: 500,
            }}>{c}</span>
          ))}
        </div>

        {/* Grid */}
        <div style={{
          display: "grid",
          gridTemplateColumns: "repeat(auto-fill, minmax(260px, 1fr))",
          gap: 16, padding: "8px 20px 24px",
        }}>
          {cards.map((card, i) => {
            const duration =
              card.duration
              || `${String(Math.floor(((i * 7919) % 18) + 4)).padStart(2, "0")}:${String(((i * 13) % 60)).padStart(2, "0")}`;
            return (
              <div key={i} style={{display: "flex", flexDirection: "column", gap: 10, position: "relative"}}>
                <div style={{
                  position: "relative",
                  aspectRatio: "16 / 9",
                  borderRadius: 12, overflow: "hidden",
                  background: card.tone || "#272727",
                }}>
                  {card.isUser ? (
                    <ComposedThumb
                      imageUrl={thumbnail.imageUrl}
                      imageUrlFull={thumbnail.imageUrlFull}
                      subjectUrl={thumbnail.subjectUrl}
                      subjectUrlFull={thumbnail.subjectUrlFull}
                      avatarSubjectUrl={thumbnail.avatarSubjectUrl}
                      avatarSubjectUrlFull={thumbnail.avatarSubjectUrlFull}
                      avatarOverlay={thumbnail.avatarOverlay}
                      texts={thumbnail.texts}
                      overlay={thumbnail.overlay}
                    />
                  ) : card.thumb ? (
                    <img src={card.thumb} alt=""
                         style={{position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover"}}
                         onError={(e) => { e.currentTarget.style.display = "none"; }} />
                  ) : (
                    <div style={{
                      position: "absolute", inset: 0,
                      display: "grid", placeItems: "center",
                      fontWeight: 700, fontSize: 26, color: "rgba(255,255,255,0.18)",
                      textTransform: "uppercase", padding: 20, textAlign: "center",
                      lineHeight: 1.05,
                      background: `linear-gradient(135deg, ${card.tone}cc 0%, ${card.tone} 100%)`,
                    }}>
                      {card.title.split(" ").slice(0, 3).join(" ")}
                    </div>
                  )}
                  <div style={{
                    position: "absolute", bottom: 6, right: 6,
                    background: "rgba(0,0,0,0.85)", color: "#fff",
                    padding: "2px 5px", borderRadius: 4,
                    fontSize: 11, fontWeight: 600, fontFamily: "system-ui",
                  }}>
                    {duration}
                  </div>
                </div>
                <div style={{display: "flex", gap: 10}}>
                  {card.isUser ? (
                    <div style={{
                      width: 36, height: 36, borderRadius: "50%", flexShrink: 0,
                      overflow: "hidden", background: "#404040",
                    }}>
                      {userAvatarUrl ? (
                        <img src={userAvatarUrl} alt="" referrerPolicy="no-referrer"
                             style={{width: "100%", height: "100%", objectFit: "cover"}} />
                      ) : null}
                    </div>
                  ) : (
                    <div style={{
                      width: 36, height: 36, borderRadius: "50%", flexShrink: 0,
                      background: channelColor(card.channel || ""),
                    }} />
                  )}
                  <div style={{minWidth: 0, flex: 1}}>
                    <div style={{
                      fontSize: 14, fontWeight: 600, lineHeight: 1.3,
                      color: "#fff",
                      display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical",
                      overflow: "hidden",
                    }}>
                      {card.title}
                    </div>
                    <div style={{fontSize: 12, color: "#aaa", marginTop: 4}}>{card.channel}</div>
                    <div style={{fontSize: 12, color: "#aaa"}}>
                      {card.views} visualizações · há {card.time}
                    </div>
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
};

window.Thumbnail = Thumbnail;
window.FacePlaceholder = FacePlaceholder;
window.ComposedThumb = ComposedThumb;
window.YouTubePreviewModal = YouTubePreviewModal;
window.DEFAULT_OVERLAY = DEFAULT_OVERLAY;
