import type { BrandProfile, PostSequenceItem, Project } from "@/types/workflow";
import { getPostPreviewSnippet } from "@/lib/context/format-sequence-context";
import type { WebsiteIntelligence } from "@/lib/context/website-intelligence";
import type { ImageBrief } from "@/lib/generation/image-brief";
import { buildEnterpriseImagePrompt } from "@/lib/generation/enterprise-image-prompt";
import {
  resolveBrandVisualStyle,
  buildSaaSMarketingImageStyleBlock,
  type BrandVisualStyle,
} from "@/lib/generation/brand-visual-style";
import {
  resolveDynamicProductConfig,
  type DynamicProductConfiguration,
} from "@/lib/generation/dynamic-product-config";
import {
  buildLogoBlock,
  buildRightPanelVisual,
  escapeXml,
  featureIconSvg,
  multilineTextSvg,
  wrapText,
} from "@/lib/generation/brand-svg-shared";
import {
  resolveBannerLayoutId,
  resolveBannerTypography,
  type BannerLayoutId,
} from "@/lib/generation/banner-layouts";
import type { BannerScenePlan } from "@/lib/generation/scene-planner";
import type { PostBannerContent } from "@/lib/generation/banner-post-content";

export interface StoryContextSections {
  currentStory: string;
  problem: string;
  impact: string;
  brandResponse: string;
  keyTheme: string;
}

export interface SocialImageContext {
  companyName: string;
  industry: string;
  headline: string;
  subheadline: string;
  category: string;
  logoDataUrl: string | null;
  captionExcerpt: string;
  accentColor: string;
  primaryColor: string;
  keyStat: string | null;
  visualConcept: string;
  problemTheme: string;
  brandResponse: string;
  brandStyle: BrandVisualStyle;
  website: string;
  websiteScraped: boolean;
  product: DynamicProductConfiguration;
  /** Unique per generation — drives layout variants. */
  layoutSeed?: number;
  /** When true, prefer AI image before branded SVG so regenerate looks new. */
  forceFreshVisuals?: boolean;
  /** Gemini/OpenAI photoreal hero embedded into the branded banner panel. */
  heroImageDataUrl?: string | null;
  /** Absolute filesystem path to hero PNG (required for FFmpeg SVG rasterize). */
  heroImageFilePath?: string | null;
  /** Optional asset id so hero files can be persisted beside the banner. */
  mediaAssetId?: string;
  /** Scene-first plan (problem → industry → scene → layout). */
  scenePlan?: BannerScenePlan;
  /** Resolved layout id for this generation (may differ from seed % n when anti-repeat applies). */
  bannerLayoutId?: BannerLayoutId;
  /** Post-specific dynamic copy (headline, features, CTA sub — unique per post). */
  postBannerContent?: PostBannerContent;
  /** Sequence beat index (1-based) for layout spread across campaign posts. */
  sequenceIndex?: number;
}

/** Truncate on a word boundary — never mid-word with "…". */
function truncate(value: string, max: number): string {
  const trimmed = value.trim().replace(/\s+/g, " ");
  if (trimmed.length <= max) return trimmed;
  const cut = trimmed.slice(0, max);
  const lastSpace = cut.lastIndexOf(" ");
  const base = (lastSpace > Math.floor(max * 0.55) ? cut.slice(0, lastSpace) : cut).replace(
    /[.,;:]+$/,
    "",
  );
  return `${base}.`;
}

function hookFromCaption(caption: string): string | null {
  const match = caption.match(/\*\*([^*]+)\*\*/);
  return match?.[1]?.trim() ?? null;
}

function excerptFromCaption(caption: string): string {
  const cleaned = caption.replace(/#\w+/g, "").trim();
  const sentences = cleaned.split(/(?<=[.!?])\s+/).filter((s) => s.length > 30);
  const best =
    sentences.find((s) => /\d+%|\d+\+?\s*hours?|faster|automation/i.test(s)) ?? sentences[0];
  return truncate(best ?? cleaned, 200);
}

function keyStatFromCaption(caption: string): string | null {
  const match =
    caption.match(/\d+%[^.\n]{0,40}/) ?? caption.match(/\d+\+?\s*hours?[^.\n]{0,30}/i);
  return match ? truncate(match[0].trim(), 40) : null;
}

function visualConceptFromBrand(
  brandStyle: BrandVisualStyle,
  _industry: string,
  _storyMood: string,
  briefConcept?: string,
): string {
  if (briefConcept?.trim()) return briefConcept.trim();
  return (
    brandStyle.productVisualHint ||
    "modern corporate managers reviewing a clean operations dashboard with soft natural light — no paper fax distress"
  );
}

export function buildSocialImageContext(input: {
  project: Project;
  brand: BrandProfile;
  sequenceItem: PostSequenceItem;
  caption: string;
  brief?: ImageBrief | null;
  storySections?: StoryContextSections;
  website?: WebsiteIntelligence | null;
  layoutSeed?: number;
  forceFreshVisuals?: boolean;
  scenePlan?: BannerScenePlan;
  bannerLayoutId?: BannerLayoutId;
  postBannerContent?: PostBannerContent;
  sequenceIndex?: number;
  mediaAssetId?: string;
}): SocialImageContext {
  const companyName =
    input.brand.companyName || input.website?.companyName || input.project.name;
  const industry = input.brand.industry || input.project.industry || "B2B";
  const category = input.sequenceItem.tag?.trim() || "Social post";
  const captionExcerpt = excerptFromCaption(input.caption);
  const sections = input.storySections;
  const brandStyle = resolveBrandVisualStyle(
    input.brand,
    input.project,
    {
      problem: sections?.problem,
      impact: sections?.impact,
      brandResponse: sections?.brandResponse,
    },
    input.website,
  );

  const product = resolveDynamicProductConfig({
    brand: input.brand,
    project: input.project,
    website: input.website,
    sequenceTitle: input.sequenceItem.title,
    problem: sections?.problem,
    impact: sections?.impact,
    brandResponse: sections?.brandResponse,
  });

  // Prefer per-post banner content / brief / caption — NEVER force the same
  // product.primaryHeadline onto every post (that caused identical creatives).
  const headline =
    input.postBannerContent?.headline?.trim() ||
    input.brief?.headline?.trim() ||
    hookFromCaption(input.caption) ||
    input.sequenceItem.title?.replace(/^Post \d+ — /, "").trim() ||
    sections?.keyTheme?.split("·").pop()?.trim() ||
    product.primaryHeadline ||
    companyName;

  const subheadline =
    input.postBannerContent?.subheadline?.trim() ||
    input.brief?.subheadline?.trim() ||
    sections?.impact?.slice(0, 200) ||
    sections?.problem?.slice(0, 200) ||
    product.subheadline ||
    captionExcerpt ||
    input.sequenceItem.summary?.trim() ||
    getPostPreviewSnippet(input.sequenceItem);

  const problemTheme = sections?.problem?.slice(0, 120) || subheadline;
  const brandResponse = sections?.brandResponse?.slice(0, 160) || "";

  const logoDataUrl =
    input.brand.logoDataUrl && input.brand.logoDataUrl.length < 2_500_000
      ? input.brand.logoDataUrl
      : null;

  return {
    companyName,
    industry,
    headline: truncate(headline, 72),
    subheadline: truncate(subheadline, 200),
    category,
    logoDataUrl,
    captionExcerpt,
    accentColor: brandStyle.accentColor,
    primaryColor: brandStyle.primaryColor,
    keyStat:
      input.brief?.keyStat ??
      product.scrapedMetrics[0] ??
      keyStatFromCaption(input.caption),
    visualConcept: product.modernVisualDirection || brandStyle.productVisualHint,
    problemTheme,
    brandResponse,
    brandStyle,
    website: brandStyle.website,
    websiteScraped: Boolean(input.website?.ok),
    product,
    layoutSeed: input.layoutSeed ?? 0,
    forceFreshVisuals: Boolean(input.forceFreshVisuals),
    mediaAssetId: input.mediaAssetId,
    scenePlan: input.scenePlan,
    bannerLayoutId:
      input.bannerLayoutId ||
      input.scenePlan?.layoutId ||
      resolveBannerLayoutId(input.layoutSeed ?? 0),
    postBannerContent: input.postBannerContent,
    sequenceIndex: input.sequenceIndex ?? 1,
  };
}

/** Branded social banner — fixed 1080×1080; layoutSeed selects composition variant. */
export function buildBrandedSocialCardSvg(ctx: SocialImageContext): string {
  const W = 1080;
  const H = 1080;
  const style = ctx.brandStyle;
  const seed = ctx.layoutSeed ?? 0;
  const layoutId =
    ctx.bannerLayoutId ||
    ctx.scenePlan?.layoutId ||
    resolveBannerLayoutId(seed);
  const type = resolveBannerTypography(seed);
  const ctaStyle = ctx.scenePlan?.ctaStyle ?? "rect";
  const features = [
    ...(ctx.postBannerContent?.features?.length
      ? ctx.postBannerContent.features.map((f) => ({
          label: f.label,
          detail: f.detail,
          accent: false,
          icon: f.icon,
        }))
      : style.features
    ).slice(
      0,
      layoutId === "feature_focused" ||
        layoutId === "split_card" ||
        layoutId === "infographic" ||
        layoutId === "timeline"
        ? 4
        : 3,
    ),
  ];
  if (features.length > 1) {
    const rot = seed % features.length;
    features.push(...features.splice(0, rot));
  }

  const headlineSource =
    ctx.postBannerContent?.headline ||
    ctx.product?.primaryHeadline ||
    ctx.headline.trim() ||
    style.heroHeadline.join(" ");
  const headlineLines = wrapText(
    headlineSource.toUpperCase(),
    layoutId === "center_cta" ? 28 : 26,
    layoutId === "statistics_focused" ? 2 : 3,
  );
  const subheadlineSource =
    ctx.postBannerContent?.subheadline ||
    ctx.product?.subheadline ||
    ctx.subheadline ||
    style.tagline ||
    style.ctaSubline;
  // Max 2 lines for description paragraphs (spacing/hierarchy rule).
  const subLines = wrapText(subheadlineSource, 42, 2);
  const taglineLines = wrapText(style.tagline || ctx.companyName, 40, 2);

  const mirrored = layoutId === "left_image";
  const isFullBleed = layoutId === "full_bleed";
  const isTopHero = layoutId === "top_hero";
  const isBottomHero = layoutId === "bottom_hero";
  const isSplitCard = layoutId === "split_card";
  const isInfographic = layoutId === "infographic";
  const isTimeline = layoutId === "timeline";
  const isDashboard = layoutId === "enterprise_dashboard";
  const textX =
    isFullBleed || isTopHero || isBottomHero || isSplitCard || isInfographic || isTimeline
      ? 48
      : mirrored
        ? 560
        : 48;
  const panelX = mirrored ? 40 : 560;
  const showSidePanel =
    layoutId !== "center_cta" &&
    !isFullBleed &&
    !isTopHero &&
    !isBottomHero &&
    !isInfographic &&
    !isTimeline &&
    !isDashboard;
  const hasLogo = Boolean(ctx.logoDataUrl);
  // Exact brand logo is always top-right for consistency with FFmpeg overlay path.
  const logoPlacement = ctx.scenePlan?.logoPlacement ?? "top_right";
  const logoX =
    logoPlacement === "top_center"
      ? 410
      : logoPlacement === "top_left"
        ? layoutId === "center_cta"
          ? 410
          : isFullBleed
            ? 48
            : mirrored
              ? 560
              : 48
        : 760;
  const logo = buildLogoBlock(ctx, {
    x: logoX,
    y: isTopHero ? 560 : 28,
    maxWidth: hasLogo ? 260 : 220,
    maxHeight: hasLogo ? 96 : 64,
  });

  // Headline starts below dedicated logo-safe area (professional whitespace).
  const headlineY = isTopHero
    ? 680
    : isBottomHero
      ? 160
      : layoutId === "center_cta"
        ? 220
        : layoutId === "statistics_focused" || isDashboard
          ? 160
          : isFullBleed
            ? 200
            : isTimeline
              ? 150
              : hasLogo
                ? 150
                : 140;
  const headlineAnchor = layoutId === "center_cta" ? ' text-anchor="middle"' : "";
  const headlineX = layoutId === "center_cta" ? 540 : textX;
  const headlineFill = isFullBleed ? "#ffffff" : style.primaryColor;
  const headlineAccent = style.accentColor;
  const headlineSvg = headlineLines
    .map((line, i) => {
      const fill = i === 0 ? headlineFill : headlineAccent;
      return `<text x="${headlineX}" y="${headlineY + i * type.headlineLineHeight}"${headlineAnchor} fill="${fill}" font-family="${type.headlineFont}" font-size="${type.headlineSize}" font-weight="bold" letter-spacing="${type.letterSpacing}">${escapeXml(line)}</text>`;
    })
    .join("");

  const subY = headlineY + headlineLines.length * type.headlineLineHeight + 16;
  const subFill = isFullBleed ? "#e2e8f0" : "#475569";
  const subSvg =
    layoutId === "center_cta"
      ? subLines
          .map(
            (line, i) =>
              `<text x="540" y="${subY + i * 22}" text-anchor="middle" fill="#475569" font-family="${type.bodyFont}" font-size="${type.subSize}" font-weight="600">${escapeXml(line)}</text>`,
          )
          .join("")
      : multilineTextSvg(textX, subY, subLines, {
          fontSize: type.subSize,
          fill: subFill,
          lineHeight: 22,
          fontWeight: "600",
        });

  const keyStat = (ctx.keyStat || style.footerBenefits[0] || "").trim();
  const statsBlock =
    layoutId === "statistics_focused" && keyStat
      ? `
  <rect x="${textX}" y="${subY + subLines.length * 22 + 16}" width="480" height="88" rx="14" fill="${style.primaryColor}" opacity="0.08"/>
  <text x="${textX + 24}" y="${subY + subLines.length * 22 + 52}" fill="${style.primaryColor}" font-family="${type.headlineFont}" font-size="32" font-weight="bold">${escapeXml(keyStat.slice(0, 28))}</text>
  <text x="${textX + 24}" y="${subY + subLines.length * 22 + 78}" fill="#64748b" font-family="${type.bodyFont}" font-size="13" font-weight="600">Proof point for decision-makers</text>`
      : "";

  const featureYStart =
    layoutId === "statistics_focused" && keyStat
      ? subY + subLines.length * 22 + 120
      : subY + subLines.length * 22 + (layoutId === "feature_focused" ? 24 : 32);
  const featureLabelFill = isFullBleed ? "#ffffff" : style.primaryColor;
  const featureDetailFill = isFullBleed ? "#cbd5e1" : "#64748b";
  const useFeatureCards =
    layoutId === "feature_focused" || isSplitCard || layoutId === "center_cta" || isInfographic;

  let featureBlocks = "";
  if (isTimeline) {
    featureBlocks = features
      .slice(0, 4)
      .map((feat, i) => {
        const x = 60 + i * 250;
        const y = 420;
        const icon = featureIconSvg(style.vertical, feat.icon, x + 100, y + 28, style.primaryColor, 40);
        const line =
          i < Math.min(features.length, 4) - 1
            ? `<line x1="${x + 130}" y1="${y + 28}" x2="${x + 230}" y2="${y + 28}" stroke="${style.accentColor}" stroke-width="3" stroke-dasharray="6 4"/>`
            : "";
        return `${line}${icon}
  <text x="${x + 100}" y="${y + 80}" text-anchor="middle" fill="${style.primaryColor}" font-family="${type.bodyFont}" font-size="13" font-weight="700">${escapeXml(feat.label.toUpperCase().slice(0, 18))}</text>`;
      })
      .join("");
  } else if (isDashboard) {
    featureBlocks = `
  <rect x="48" y="320" width="984" height="360" rx="18" fill="${style.primaryColor}" opacity="0.06"/>
  ${features
    .slice(0, 4)
    .map((feat, i) => {
      const col = i % 2;
      const row = Math.floor(i / 2);
      const x = 80 + col * 470;
      const y = 350 + row * 150;
      const icon = featureIconSvg(style.vertical, feat.icon, x + 28, y + 40, style.primaryColor, 44);
      return `<rect x="${x}" y="${y}" width="440" height="130" rx="14" fill="white" stroke="${style.primaryColor}" stroke-opacity="0.12"/>
  ${icon}
  <text x="${x + 90}" y="${y + 42}" fill="${style.primaryColor}" font-family="${type.bodyFont}" font-size="16" font-weight="700">${escapeXml(feat.label.toUpperCase())}</text>
  <text x="${x + 90}" y="${y + 70}" fill="#64748b" font-family="${type.bodyFont}" font-size="13">${escapeXml((feat.detail || "").slice(0, 48))}</text>`;
    })
    .join("")}`;
  } else if (layoutId === "center_cta") {
    featureBlocks = features
      .slice(0, 3)
      .map((feat, i) => {
        const col = i % 3;
        const x = 80 + col * 340;
        const y = 500;
        const labelLines = wrapText(feat.label, 22, 1);
        const detailLines = wrapText(feat.detail, 28, 2);
        const icon = featureIconSvg(style.vertical, feat.icon, x + 18, y + 22, style.primaryColor, 40);
        return `<rect x="${x}" y="${y}" width="300" height="130" rx="12" fill="white" stroke="${style.primaryColor}" stroke-opacity="0.15"/>
  ${icon}
  ${multilineTextSvg(x + 52, y + 16, labelLines, { fontSize: type.featureLabelSize, fontWeight: "bold", fill: style.primaryColor, lineHeight: 18 })}
  ${multilineTextSvg(x + 24, y + 52, detailLines, { fontSize: type.featureDetailSize, fill: "#64748b", lineHeight: 17 })}`;
      })
      .join("");
  } else {
    featureBlocks = features
      .map((feat, i) => {
        const rowH = useFeatureCards ? 72 : 80;
        const y = featureYStart + i * rowH;
        const labelLines = wrapText(feat.label.toUpperCase(), 28, 1);
        const detailLines = wrapText(feat.detail, 38, 1);
        const icon = featureIconSvg(
          style.vertical,
          feat.icon,
          textX + 22,
          y + 28,
          isFullBleed ? style.accentColor : style.primaryColor,
          36,
        );
        const card =
          useFeatureCards && !isFullBleed
            ? `<rect x="${textX}" y="${y}" width="${isInfographic ? 980 : 480}" height="${rowH - 8}" rx="10" fill="white" stroke="${style.primaryColor}" stroke-opacity="0.12"/>`
            : !isFullBleed && i > 0
              ? `<line x1="${textX + 8}" y1="${y - 4}" x2="${textX + 470}" y2="${y - 4}" stroke="${style.primaryColor}" stroke-opacity="0.18" stroke-dasharray="5 4"/>`
              : "";
        const labelSvg = multilineTextSvg(textX + 56, y + 18, labelLines, {
          fontSize: type.featureLabelSize,
          fontWeight: "bold",
          fill: featureLabelFill,
          lineHeight: 16,
        });
        const detailSvg = multilineTextSvg(textX + 56, y + 40, detailLines, {
          fontSize: type.featureDetailSize,
          fill: featureDetailFill,
          lineHeight: 16,
        });
        return `${card}${icon}${labelSvg}${detailSvg}`;
      })
      .join("");
  }

  const panelHeight =
    layoutId === "feature_focused" || isSplitCard
      ? 440
      : layoutId === "statistics_focused"
        ? 460
        : 500;
  const rightPanel =
    isTopHero
      ? buildRightPanelVisual(ctx, { x: 40, y: 40, width: 1000, height: 480 })
      : isBottomHero
        ? buildRightPanelVisual(ctx, { x: 40, y: 540, width: 1000, height: 380 })
        : isFullBleed
          ? buildRightPanelVisual(ctx, { x: 420, y: 120, width: 620, height: 760 })
          : isTimeline
            ? buildRightPanelVisual(ctx, { x: 40, y: 560, width: 1000, height: 280 })
            : isDashboard || isInfographic
              ? ""
              : showSidePanel
                ? buildRightPanelVisual(ctx, {
                    x: panelX,
                    y: layoutId === "feature_focused" || isSplitCard ? 200 : 160,
                    width: isSplitCard ? 460 : 480,
                    height: panelHeight,
                  })
                : buildRightPanelVisual(ctx, { x: 140, y: 680, width: 800, height: 200 });

  const motif = ctx.scenePlan?.backgroundMotif;
  const bgMotifSvg =
    motif === "soft_orbs"
      ? `<circle cx="920" cy="180" r="120" fill="${style.accentColor}" opacity="0.12"/><circle cx="160" cy="900" r="160" fill="${style.primaryColor}" opacity="0.08"/>`
      : motif === "grid_mesh"
        ? `<g opacity="0.08" stroke="${style.primaryColor}" stroke-width="1">${Array.from({ length: 8 }, (_, i) => `<line x1="${80 + i * 120}" y1="0" x2="${80 + i * 120}" y2="1080"/>`).join("")}</g>`
        : motif === "diagonal_split"
          ? `<polygon points="700,0 1080,0 1080,1080 520,1080" fill="${style.primaryColor}" opacity="0.06"/>`
          : "";

  const ctaLabel = (style.ctaLine || "LEARN MORE").slice(0, 28).toUpperCase();
  const websiteDisplay = (style.website || ctx.website || "")
    .replace(/^https?:\/\//i, "")
    .replace(/\/$/, "");
  const ctaSub = (
    ctx.postBannerContent?.ctaSubline ||
    style.ctaSubline ||
    (websiteDisplay ? websiteDisplay : style.primaryService) ||
    "GET STARTED"
  ).slice(0, 42);
  const ctaY = isTopHero
    ? 880
    : layoutId === "center_cta"
      ? 760
      : isBottomHero
        ? 400
        : isTimeline
          ? 880
          : isDashboard
            ? 860
            : isSplitCard
              ? 780
              : 780;
  const preferAccent =
    ctaStyle === "dual_tone" ||
    layoutId === "center_cta" ||
    layoutId === "statistics_focused" ||
    isFullBleed;
  const ctaFill = preferAccent ? style.accentColor : style.primaryColor;
  const ctaText =
    ctaStyle === "outline"
      ? style.primaryColor
      : layoutId === "center_cta" || layoutId === "statistics_focused"
        ? style.primaryColor
        : "white";
  const ctaSubFill =
    ctaStyle === "outline"
      ? style.accentColor
      : layoutId === "center_cta" || layoutId === "statistics_focused"
        ? style.primaryColor
        : isFullBleed
          ? "#e2e8f0"
          : style.accentColor;
  const ctaWidth =
    ctaStyle === "wide_bar" ? (layoutId === "center_cta" ? 640 : 520) : layoutId === "center_cta" ? 520 : 480;
  const ctaX = layoutId === "center_cta" ? (W - ctaWidth) / 2 : textX;
  const ctaRx = ctaStyle === "pill" ? 36 : ctaStyle === "wide_bar" ? 8 : 12;
  const ctaStroke =
    ctaStyle === "outline"
      ? ` fill="none" stroke="${style.primaryColor}" stroke-width="3"`
      : ` fill="${ctaFill}"`;
  const ctaBlock = `
  <rect x="${ctaX}" y="${ctaY}" width="${ctaWidth}" height="${ctaStyle === "wide_bar" ? 84 : 76}" rx="${ctaRx}"${ctaStroke}/>
  <text x="${ctaX + 24}" y="${ctaY + 34}" fill="${ctaText}" font-family="${type.bodyFont}" font-size="${type.ctaSize}" font-weight="bold">${escapeXml(ctaLabel)}</text>
  <text x="${ctaX + 24}" y="${ctaY + 58}" fill="${ctaSubFill}" font-family="${type.bodyFont}" font-size="13" font-weight="600">${escapeXml(ctaSub)}</text>`;

  const fullBleedScrim = isFullBleed
    ? `<rect x="0" y="0" width="460" height="1080" fill="${style.primaryColor}" opacity="0.82"/>`
    : "";
  const seedMark = `<desc id="regen-${seed}">layout-${layoutId}</desc>`;

  // Contact pills + website (Gventure-style footer).
  const phone = style.contactPhone?.trim();
  const email = style.contactEmail?.trim();
  const contactPillY = isFullBleed || isTopHero ? 1000 : 980;
  const pills: Array<{ label: string; w: number }> = [];
  if (phone) pills.push({ label: phone, w: Math.min(280, 48 + phone.length * 9) });
  if (email) pills.push({ label: email, w: Math.min(320, 48 + email.length * 8) });
  let pillX = textX;
  const contactPillsSvg = pills
    .map((p) => {
      const svg = `<rect x="${pillX}" y="${contactPillY}" width="${p.w}" height="36" rx="18" fill="${isFullBleed ? "rgba(255,255,255,0.18)" : style.primaryColor}"/>
  <text x="${pillX + p.w / 2}" y="${contactPillY + 23}" text-anchor="middle" fill="white" font-family="${type.bodyFont}" font-size="13" font-weight="600">${escapeXml(p.label)}</text>`;
      pillX += p.w + 12;
      return svg;
    })
    .join("\n  ");
  const websiteY = contactPillY + (pills.length ? 48 : 8);
  const websiteSvg = websiteDisplay
    ? `<text x="${layoutId === "center_cta" ? 540 : textX}" y="${websiteY}"${layoutId === "center_cta" ? ' text-anchor="middle"' : ""} fill="${isFullBleed ? "#e2e8f0" : style.primaryColor}" font-family="${type.bodyFont}" font-size="14" font-weight="700">🌐  https://${escapeXml(websiteDisplay)}</text>`
    : "";

  const taglineX =
    layoutId === "center_cta"
      ? 540
      : mirrored
        ? hasLogo
          ? 840
          : 560
        : hasLogo
          ? 328
          : 48;
  const taglineBlock =
    layoutId === "center_cta"
      ? taglineLines
          .map(
            (line, i) =>
              `<text x="540" y="${140 + i * 15}" text-anchor="middle" fill="#64748b" font-family="${type.bodyFont}" font-size="12" font-weight="600">${escapeXml(line)}</text>`,
          )
          .join("")
      : isTopHero || isFullBleed
        ? ""
        : multilineTextSvg(taglineX, 48, taglineLines, {
            fontSize: 12,
            fill: "#64748b",
            lineHeight: 15,
            fontWeight: "600",
          });

  const headerBar =
    isTopHero || isBottomHero || isFullBleed
      ? ""
      : `<rect x="0" y="0" width="${W}" height="${hasLogo ? 140 : 120}" fill="white"/>`;

  const svg = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${W}" height="${H}" viewBox="0 0 ${W} ${H}">
  ${seedMark}
  <defs>
    <linearGradient id="photoGrad" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:${style.primaryColor};stop-opacity:0.12"/>
      <stop offset="50%" style="stop-color:${style.accentColor};stop-opacity:0.18"/>
      <stop offset="100%" style="stop-color:#e2e8f0"/>
    </linearGradient>
  </defs>
  <rect width="${W}" height="${H}" fill="${style.lightBg}"/>
  ${headerBar}
  ${bgMotifSvg}
  ${rightPanel}
  ${fullBleedScrim}
  ${logo}
  ${taglineBlock}
  ${headlineSvg}
  ${subSvg}
  ${statsBlock}
  ${featureBlocks}
  ${ctaBlock}
  ${contactPillsSvg}
  ${websiteSvg}
</svg>`;

  return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
}

/** Expose layout id for analytics / QA consumers. */
export function getBannerLayoutId(ctx: SocialImageContext): BannerLayoutId {
  return ctx.bannerLayoutId || ctx.scenePlan?.layoutId || resolveBannerLayoutId(ctx.layoutSeed ?? 0);
}

export function buildContextualImagePrompt(
  ctx: SocialImageContext,
  sequenceItem: PostSequenceItem,
  sections?: StoryContextSections,
  mediaSummaryBrief?: string,
): string {
  const tag = sequenceItem.tag?.trim() || "B2B marketing";
  const enterprise = buildEnterpriseImagePrompt({
    companyName: ctx.companyName,
    industry: ctx.industry,
    problem: sections?.problem || ctx.problemTheme,
    impact: sections?.impact || ctx.subheadline,
    solution: ctx.brandResponse || ctx.brandStyle.ctaLine,
    headline: ctx.headline,
    subheadline: ctx.subheadline,
    visualConcept: ctx.visualConcept,
    brandStyle: ctx.brandStyle,
    theme: sections?.keyTheme || tag,
    mediaSummaryBrief,
    product: ctx.product,
  });

  const flyerLayout = buildSaaSMarketingImageStyleBlock(
    ctx.brandStyle,
    ctx.companyName,
    ctx.industry,
  );

  const layoutName = resolveBannerLayoutId(ctx.layoutSeed ?? 0);
  const regenDirective =
    ctx.forceFreshVisuals || ctx.layoutSeed
      ? [
          "",
          "## Regeneration uniqueness (mandatory)",
          `Unique render token: ${ctx.layoutSeed ?? 0}-${Date.now().toString(36)}.`,
          `Preferred composition: ${layoutName} (do not reuse a previous frame).`,
          "Generate a completely NEW 1080×1080 social banner illustration.",
          "Change camera angle, subject pose, icon placement, background motif, and secondary props.",
          "Keep brand colors, company feel, and readable marketing hierarchy.",
          "Do NOT recreate the previous image with minor tweaks — produce a distinct creative.",
        ].join("\n")
      : "";

  return [enterprise, "", "## Zone reinforcement", flyerLayout, regenDirective]
    .filter(Boolean)
    .join("\n");
}
