/**
 * Layout Exporter Utility v2
 *
 * @deprecated This file is deprecated. Use the modular structure in `layoutExporter/` instead.
 * Import from `@/utils/layoutExporter` which now exports from the modular files:
 * - exportLayout.ts - Main export function
 * - placeholders.ts - Available placeholders for custom HTML
 * - types.ts - Type definitions and type guards
 * - utils.ts - Utility functions
 * - htmlGenerators.ts - HTML generation functions
 * - cssGenerators.ts - CSS generation functions
 * - responsiveGenerators.ts - Responsive CSS generation
 *
 * This file is kept for reference only and may be removed in a future version.
 */

import type {
  CanvasElement,
  PriceElement,
  CurrencyElement,
  DiscountBadgeElement,
  TextElement,
  VariablePriceRangeElement,
  ElementType,
  ContainerSettings,
  ResponsiveValue,
} from "@/types";
import { isResponsiveValue, DEFAULT_FONT_VALUE, getFontCssValue } from "@/types";
import { analyzeLayout, type AlignmentInfo, type ContainerBounds } from "./layoutAnalyzer";

// ==========================================================================
// Responsive Breakpoint Configuration
// ==========================================================================

/** CSS media query breakpoints */
const BREAKPOINTS = {
  tablet: 768, // max-width for tablet
  mobile: 480, // max-width for mobile
} as const;

// Type guards
const isPriceElement = (el: CanvasElement): el is PriceElement => el.type === "regularPrice" || el.type === "salePrice";

const isVariablePriceRangeElement = (el: CanvasElement): el is VariablePriceRangeElement => el.type === "variablePriceRange";

const isCurrencyElement = (el: CanvasElement): el is CurrencyElement => el.type === "currencySymbol";

const isDiscountBadgeElement = (el: CanvasElement): el is DiscountBadgeElement => el.type === "discountBadge";

const isTextElement = (el: CanvasElement): el is TextElement => el.type === "text";

/**
 * Helper to get desktop value from a responsive or plain value
 */
function getDesktopValue<T>(value: T | ResponsiveValue<T> | undefined, fallback: T): T {
  if (value === undefined) return fallback;
  if (isResponsiveValue(value)) {
    return value.desktop;
  }
  return value as T;
}

// Export result
export interface ExportResult {
  html: string;
  css: string;
  webComponentHtml: string;
  customJs?: string;
  /** Whether this layout uses CountUp animation (requires countUp.min.js) */
  usesCountUp?: boolean;
  /** Generated CountUp initialization code (combined with customJs if present) */
  countUpJs?: string;
}

/**
 * Generate CSS class name from element type
 */
function getClassName(type: ElementType): string {
  const classMap: Record<ElementType, string> = {
    regularPrice: "oppb-regular-price",
    salePrice: "oppb-sale-price",
    variablePriceRange: "oppb-variable-range",
    currencySymbol: "oppb-currency",
    discountBadge: "oppb-discount-badge",
    text: "oppb-text",
  };
  return classMap[type] || "oppb-element";
}

/**
 * Generate CSS for typography (desktop values only - for base CSS)
 */
function generateTypographyCSS(el: CanvasElement): string {
  const { typography } = el;
  const rules: string[] = [];

  // Only add font-family if not using default (which inherits from theme)
  const fontCssValue = getFontCssValue(typography.fontFamily);
  if (fontCssValue) {
    rules.push(`font-family: ${fontCssValue}`);
  }
  rules.push(`font-size: ${typography.fontSize.desktop}px`);
  rules.push(`font-weight: ${typography.fontWeight.desktop}`);
  if (typography.fontStyle !== "normal") {
    rules.push(`font-style: ${typography.fontStyle}`);
  }
  rules.push(`line-height: ${typography.lineHeight}`);
  if (typography.letterSpacing.desktop !== 0) {
    rules.push(`letter-spacing: ${typography.letterSpacing.desktop}px`);
  }
  if (typography.textTransform !== "none") {
    rules.push(`text-transform: ${typography.textTransform}`);
  }
  if (typography.textDecoration !== "none") {
    rules.push(`text-decoration: ${typography.textDecoration}`);
  }

  return rules.join(";\n  ");
}

/**
 * Generate responsive typography CSS rules for a specific breakpoint
 * Returns only the rules that differ from desktop
 */
function generateResponsiveTypographyRules(el: CanvasElement, breakpoint: "tablet" | "mobile"): string[] {
  const { typography } = el;
  const rules: string[] = [];

  // Only add rules if they differ from desktop
  if (typography.fontSize[breakpoint] !== typography.fontSize.desktop) {
    rules.push(`font-size: ${typography.fontSize[breakpoint]}px`);
  }
  if (typography.fontWeight[breakpoint] !== typography.fontWeight.desktop) {
    rules.push(`font-weight: ${typography.fontWeight[breakpoint]}`);
  }
  if (typography.letterSpacing[breakpoint] !== typography.letterSpacing.desktop) {
    rules.push(`letter-spacing: ${typography.letterSpacing[breakpoint]}px`);
  }

  return rules;
}

/**
 * Generate responsive border CSS rules for a specific breakpoint
 * Returns only the rules that differ from desktop
 */
function generateResponsiveBorderRules(el: CanvasElement, breakpoint: "tablet" | "mobile"): string[] {
  const { border } = el;
  const rules: string[] = [];

  // Only add rules if they differ from desktop
  if (border.width[breakpoint] !== border.width.desktop) {
    if (border.width[breakpoint] > 0) {
      rules.push(`border-width: ${border.width[breakpoint]}px`);
    } else {
      rules.push(`border-width: 0`);
    }
  }

  return rules;
}

/**
 * Generate responsive padding CSS rules for a specific breakpoint
 * Returns only the rules that differ from desktop
 */
function generateResponsivePaddingRules(el: CanvasElement, breakpoint: "tablet" | "mobile"): string[] {
  const { padding } = el;
  const rules: string[] = [];

  // Check if any padding value differs from desktop
  const topDiff = padding.top[breakpoint] !== padding.top.desktop;
  const rightDiff = padding.right[breakpoint] !== padding.right.desktop;
  const bottomDiff = padding.bottom[breakpoint] !== padding.bottom.desktop;
  const leftDiff = padding.left[breakpoint] !== padding.left.desktop;

  if (topDiff || rightDiff || bottomDiff || leftDiff) {
    rules.push(
      `padding: ${padding.top[breakpoint]}px ${padding.right[breakpoint]}px ${padding.bottom[breakpoint]}px ${padding.left[breakpoint]}px`,
    );
  }

  return rules;
}

/**
 * Generate responsive margin CSS rules for a specific breakpoint
 * Returns only the rules that differ from desktop
 */
function generateResponsiveMarginRules(el: CanvasElement, breakpoint: "tablet" | "mobile"): string[] {
  const { margin } = el;
  const rules: string[] = [];

  // Check if any margin value differs from desktop
  const topDiff = margin.top[breakpoint] !== margin.top.desktop;
  const rightDiff = margin.right[breakpoint] !== margin.right.desktop;
  const bottomDiff = margin.bottom[breakpoint] !== margin.bottom.desktop;
  const leftDiff = margin.left[breakpoint] !== margin.left.desktop;

  if (topDiff || rightDiff || bottomDiff || leftDiff) {
    rules.push(
      `margin: ${margin.top[breakpoint]}px ${margin.right[breakpoint]}px ${margin.bottom[breakpoint]}px ${margin.left[breakpoint]}px`,
    );
  }

  return rules;
}

/**
 * Generate base CSS for an element (without positioning)
 */
function generateBaseElementCSS(el: CanvasElement): string {
  const rules: string[] = [];

  // Colors
  rules.push(`color: ${el.color}`);
  if (el.backgroundColor !== "transparent") {
    rules.push(`background-color: ${el.backgroundColor}`);
  }

  // Opacity
  if (el.opacity < 1) {
    rules.push(`opacity: ${el.opacity}`);
  }

  // Typography
  rules.push(generateTypographyCSS(el));

  // Border
  if (el.border.width.desktop > 0) {
    rules.push(`border: ${el.border.width.desktop}px ${el.border.style} ${el.border.color}`);
  }
  if (el.border.radius > 0) {
    rules.push(`border-radius: ${el.border.radius}px`);
  }

  // Padding
  if (el.padding.top.desktop > 0 || el.padding.right.desktop > 0 || el.padding.bottom.desktop > 0 || el.padding.left.desktop > 0) {
    rules.push(
      `padding: ${el.padding.top.desktop}px ${el.padding.right.desktop}px ${el.padding.bottom.desktop}px ${el.padding.left.desktop}px`,
    );
  }

  // Margin
  if (el.margin.top.desktop > 0 || el.margin.right.desktop > 0 || el.margin.bottom.desktop > 0 || el.margin.left.desktop > 0) {
    rules.push(`margin: ${el.margin.top.desktop}px ${el.margin.right.desktop}px ${el.margin.bottom.desktop}px ${el.margin.left.desktop}px`);
  }

  // Rotation
  if (el.rotation !== 0) {
    rules.push(`transform: rotate(${el.rotation}deg)`);
  }

  return rules.join(";\n  ");
}

/**
 * Generate CSS for absolute positioned element
 * Positions are rounded to whole pixels for cleaner CSS output
 */
function generateAbsoluteCSS(el: CanvasElement, containerBounds: ContainerBounds): string {
  const rules: string[] = [];

  rules.push("position: absolute");

  // Calculate position relative to container (rounded to whole pixels)
  const relativeX = Math.round(el.position.x - containerBounds.x);
  const relativeY = Math.round(el.position.y - containerBounds.y);

  rules.push(`left: ${relativeX}px`);
  rules.push(`top: ${relativeY}px`);

  return rules.join(";\n  ");
}

/**
 * Generate HTML for a price element
 */
function generatePriceHTML(el: PriceElement, useWebComponent: boolean): string {
  const className = getClassName(el.type);
  const placeholder = el.type === "regularPrice" ? "{regularPrice}" : "{salePrice}";
  const mainPlaceholder = el.type === "regularPrice" ? "{regularPriceMain}" : "{salePriceMain}";
  const decimalPlaceholder = el.type === "regularPrice" ? "{regularPriceDecimal}" : "{salePriceDecimal}";

  // Get separator character - hardcoded in HTML since it's a design choice, not runtime data
  let separator = ".";
  if (el.decimal?.separator === "comma") {
    separator = ",";
  } else if (el.decimal?.separator === "none") {
    separator = "";
  }

  // Check if currency should be shown (default true)
  const showCurrency = el.decimal?.showCurrency ?? true;
  const currencyHtml = showCurrency
    ? useWebComponent
      ? `<span class="${className}__currency">{currencySymbol}</span>`
      : `<span class="${className}__currency">$</span>`
    : "";

  // Generate structured price HTML
  if (el.decimal?.show && el.decimal.position !== "inline") {
    if (useWebComponent) {
      // Use the configured separator directly, not a placeholder, since it's a design choice
      return `<span class="${className}">${currencyHtml}<span class="${className}__main">${mainPlaceholder}</span><span class="${className}__decimal">${separator}${decimalPlaceholder}</span></span>`;
    }
    return `<span class="${className}">${currencyHtml}<span class="${className}__main">99</span><span class="${className}__decimal">${separator}99</span></span>`;
  }

  if (useWebComponent) {
    // For inline or when decimals are disabled, use appropriate placeholders
    if (el.decimal?.show === false) {
      // No decimals - only show main price part
      return showCurrency
        ? `<span class="${className}">{currencySymbol}${mainPlaceholder}</span>`
        : `<span class="${className}">${mainPlaceholder}</span>`;
    }
    // Inline decimals - use full price placeholder with optional currency
    return showCurrency
      ? `<span class="${className}">${placeholder}</span>`
      : `<span class="${className}">${mainPlaceholder}${separator}${decimalPlaceholder}</span>`;
  }

  // Static preview (non-web-component)
  if (el.decimal?.show === false) {
    return showCurrency ? `<span class="${className}">$99</span>` : `<span class="${className}">99</span>`;
  }
  return showCurrency ? `<span class="${className}">$99.99</span>` : `<span class="${className}">99${separator}99</span>`;
}

/**
 * Generate HTML for a variable price range element
 */
function generateVariablePriceRangeHTML(el: VariablePriceRangeElement, useWebComponent: boolean): string {
  const className = "oppb-variable-range";
  const displayMode = el.displayMode || "range";
  const separator = el.separator || " – ";
  const prefixText = el.prefixText || "From ";
  const showCurrency = el.showCurrency ?? true;

  // Get separator characters for min and max decimals
  const getDecimalSeparator = (decimalSettings: VariablePriceRangeElement["minDecimal"]): string => {
    if (!decimalSettings?.separator || decimalSettings.separator === "point") {
      return ".";
    }
    if (decimalSettings.separator === "comma") {
      return ",";
    }
    return ""; // "none"
  };

  const minSeparator = getDecimalSeparator(el.minDecimal);
  const maxSeparator = getDecimalSeparator(el.maxDecimal);

  // Decimal display helpers
  const getMinPriceHTML = (withDecimal: boolean): string => {
    if (withDecimal && el.minDecimal?.show && el.minDecimal.position !== "inline") {
      if (useWebComponent) {
        const currencySpan = showCurrency ? `<span class="${className}__min-currency">{currencySymbol}</span>` : "";
        // Use the configured separator directly, not a placeholder, since it's a design choice
        return `${currencySpan}<span class="${className}__min-main">{minPriceMain}</span><span class="${className}__min-decimal">${minSeparator}{minPriceDecimal}</span>`;
      }
      const currencySpan = showCurrency ? `<span class="${className}__min-currency">$</span>` : "";
      return `${currencySpan}<span class="${className}__min-main">19</span><span class="${className}__min-decimal">${minSeparator}99</span>`;
    }
    // When decimals are hidden, use main price only (without decimal portion)
    if (useWebComponent) {
      if (el.minDecimal?.show === false) {
        // Decimals disabled - use only main price without decimal
        return showCurrency ? `{currencySymbol}{minPriceMain}` : `{minPriceMain}`;
      }
      return showCurrency ? `{minPrice}` : `{minPriceMain}`;
    }
    return showCurrency ? `$19` : `19`;
  };

  const getMaxPriceHTML = (withDecimal: boolean): string => {
    if (withDecimal && el.maxDecimal?.show && el.maxDecimal.position !== "inline") {
      if (useWebComponent) {
        const currencySpan = showCurrency ? `<span class="${className}__max-currency">{currencySymbol}</span>` : "";
        // Use the configured separator directly, not a placeholder, since it's a design choice
        return `${currencySpan}<span class="${className}__max-main">{maxPriceMain}</span><span class="${className}__max-decimal">${maxSeparator}{maxPriceDecimal}</span>`;
      }
      const currencySpan = showCurrency ? `<span class="${className}__max-currency">$</span>` : "";
      return `${currencySpan}<span class="${className}__max-main">99</span><span class="${className}__max-decimal">${maxSeparator}99</span>`;
    }
    // When decimals are hidden, use main price only (without decimal portion)
    if (useWebComponent) {
      if (el.maxDecimal?.show === false) {
        // Decimals disabled - use only main price without decimal
        return showCurrency ? `{currencySymbol}{maxPriceMain}` : `{maxPriceMain}`;
      }
      return showCurrency ? `{maxPrice}` : `{maxPriceMain}`;
    }
    return showCurrency ? `$99` : `99`;
  };

  const minHasDecimal = el.minDecimal?.show && el.minDecimal.position !== "inline";
  const maxHasDecimal = el.maxDecimal?.show && el.maxDecimal.position !== "inline";

  // Build HTML based on display mode
  let innerHtml = "";
  switch (displayMode) {
    case "range":
      innerHtml = `<span class="${className}__min">${getMinPriceHTML(
        !!minHasDecimal,
      )}</span><span class="${className}__separator">${separator}</span><span class="${className}__max">${getMaxPriceHTML(
        !!maxHasDecimal,
      )}</span>`;
      break;
    case "from":
      innerHtml = `<span class="${className}__prefix">${prefixText}</span><span class="${className}__min">${getMinPriceHTML(
        !!minHasDecimal,
      )}</span>`;
      break;
    case "up-to":
      innerHtml = `<span class="${className}__prefix">${prefixText}</span><span class="${className}__max">${getMaxPriceHTML(
        !!maxHasDecimal,
      )}</span>`;
      break;
    case "min-only":
      innerHtml = `<span class="${className}__min">${getMinPriceHTML(!!minHasDecimal)}</span>`;
      break;
    case "max-only":
      innerHtml = `<span class="${className}__max">${getMaxPriceHTML(!!maxHasDecimal)}</span>`;
      break;
  }

  return `<span class="${className}">${innerHtml}</span>`;
}

/**
 * Generate HTML for a currency element
 */
function generateCurrencyHTML(el: CurrencyElement, _useWebComponent: boolean): string {
  const className = getClassName(el.type);

  // Support custom image from media library
  if (el.useCustomImage && el.customImageUrl) {
    return `<span class="${className}"><img src="${el.customImageUrl}" alt="Currency" class="${className}__img" /></span>`;
  }

  // Legacy SVG support
  if (el.useCustomSvg && el.customSvg) {
    return `<span class="${className}">${el.customSvg}</span>`;
  }

  // Use the symbol chosen in the canvas editor (fallback to $)
  const symbol = el.symbol || "$";
  return `<span class="${className}">${symbol}</span>`;
}

/**
 * Generate HTML for a discount badge element
 */
function generateDiscountBadgeHTML(el: DiscountBadgeElement, useWebComponent: boolean): string {
  const className = getClassName(el.type);

  if (useWebComponent) {
    // Use format setting to determine placeholder
    // Only use customFormat when format is "custom"
    let content: string;
    switch (el.format) {
      case "amount":
        // Always use the amount placeholder for amount format
        content = "-{discountAmount}";
        break;
      case "custom": {
        // Use custom format string (user-defined)
        // Handle multiline: split by newlines and wrap each line in a span
        const customContent = el.customFormat || "-{discount}%";
        if (customContent.includes("\n")) {
          const lines = customContent.split("\n");
          content = lines.map((line) => `<span class="oppb-discount-line">${line}</span>`).join("");
        } else {
          content = customContent;
        }
        break;
      }
      case "percentage":
      default:
        // Always use the percentage placeholder for percentage format
        content = "-{discount}%";
        break;
    }
    return `<span class="${className}">${content}</span>`;
  }

  // Static preview based on format
  const previewText = el.format === "amount" ? "-$19.99" : "-20%";
  return `<span class="${className}">${previewText}</span>`;
}

/**
 * Generate HTML for text element
 */
function generateTextElementHTML(el: TextElement): string {
  const className = getClassName(el.type);
  const text = el.text || "";

  // Handle multiline text
  if (text.includes("\n")) {
    const lines = text.split("\n");
    const linesHtml = lines.map((line) => `<span class="oppb-text-line">${escapeHtml(line) || "&nbsp;"}</span>`).join("");
    return `<span class="${className}">${linesHtml}</span>`;
  }

  return `<span class="${className}">${escapeHtml(text)}</span>`;
}

/**
 * Escape HTML special characters
 */
function escapeHtml(text: string): string {
  const map: Record<string, string> = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': "&quot;",
    "'": "&#039;",
  };
  return text.replace(/[&<>"']/g, (m) => map[m]);
}

/**
 * Generate HTML for any element
 */
function generateElementHTML(el: CanvasElement, useWebComponent: boolean): string {
  if (!el.visible) return "";

  if (isPriceElement(el)) {
    return generatePriceHTML(el, useWebComponent);
  }
  if (isVariablePriceRangeElement(el)) {
    return generateVariablePriceRangeHTML(el, useWebComponent);
  }
  if (isCurrencyElement(el)) {
    return generateCurrencyHTML(el, useWebComponent);
  }
  if (isDiscountBadgeElement(el)) {
    return generateDiscountBadgeHTML(el, useWebComponent);
  }
  if (isTextElement(el)) {
    return generateTextElementHTML(el);
  }

  // Handle custom HTML elements or fallback
  return `<span class="oppb-element"></span>`;
}

/**
 * Generate decimal CSS if needed
 */
function generateDecimalCSS(el: PriceElement): string {
  if (!el.decimal?.show || el.decimal.position === "inline") return "";

  const className = getClassName(el.type);
  const decimalTypo = el.decimal.typography || {};
  const rules: string[] = [];

  // Only use explicit decimal fontSize if set, otherwise scale with main typography
  const hasExplicitFontSize = decimalTypo.fontSize?.desktop !== undefined;
  const decimalFontSize = hasExplicitFontSize ? decimalTypo.fontSize!.desktop : Math.round(el.typography.fontSize.desktop * 0.6);

  if (el.decimal.position === "top") {
    rules.push("vertical-align: top");
    rules.push(`font-size: ${decimalFontSize}px`);
  } else if (el.decimal.position === "superscript") {
    rules.push("vertical-align: super");
    rules.push(`font-size: ${decimalFontSize}px`);
  } else if (el.decimal.position === "baseline") {
    rules.push("vertical-align: baseline");
    rules.push(`font-size: ${decimalFontSize}px`);
  } else if (el.decimal.position === "absolute") {
    rules.push("position: absolute");
    if (el.decimal.absoluteOffset) {
      rules.push(`left: ${el.decimal.absoluteOffset.x}px`);
      rules.push(`top: ${el.decimal.absoluteOffset.y}px`);
    }
    rules.push(`font-size: ${decimalFontSize}px`);
  }

  const fontWeight = getDesktopValue(decimalTypo.fontWeight, undefined);
  if (fontWeight) {
    rules.push(`font-weight: ${fontWeight}`);
  }
  // Only add font-family if not using default (which inherits from theme)
  if (decimalTypo.fontFamily && decimalTypo.fontFamily !== DEFAULT_FONT_VALUE) {
    const decimalFontCss = getFontCssValue(decimalTypo.fontFamily);
    if (decimalFontCss) {
      rules.push(`font-family: ${decimalFontCss}`);
    }
  }
  // Font style - explicitly set to prevent inheritance from parent
  const fontStyle = decimalTypo.fontStyle ?? "normal";
  rules.push(`font-style: ${fontStyle}`);
  // Letter spacing
  const letterSpacing = getDesktopValue(decimalTypo.letterSpacing, 0);
  if (letterSpacing !== 0) {
    rules.push(`letter-spacing: ${letterSpacing}px`);
  }
  // Text decoration
  const textDecoration = decimalTypo.textDecoration ?? "none";
  if (textDecoration !== "none") {
    rules.push(`text-decoration: ${textDecoration}`);
  }
  rules.push("white-space: nowrap");

  return `.${className}__decimal {
  ${rules.join(";\n  ")};
}`;
}

/**
 * Generate responsive decimal CSS rules for price elements
 * Returns rules for tablet and mobile breakpoints
 */
function generateResponsiveDecimalRules(el: PriceElement, breakpoint: "tablet" | "mobile"): string[] {
  if (!el.decimal?.show || el.decimal.position === "inline") return [];

  const rules: string[] = [];
  const decimalTypo = el.decimal.typography || {};

  // Calculate decimal font size for this breakpoint
  // If explicit responsive decimal fontSize exists, use it; otherwise scale from main typography
  const hasExplicitFontSize = decimalTypo.fontSize !== undefined && isResponsiveValue(decimalTypo.fontSize);

  if (hasExplicitFontSize) {
    const fontSize = decimalTypo.fontSize as ResponsiveValue<number>;
    // Only add rule if different from desktop
    if (fontSize[breakpoint] !== fontSize.desktop) {
      rules.push(`font-size: ${fontSize[breakpoint]}px`);
    }
  } else {
    // Scale proportionally from main typography
    const mainFontSize = el.typography.fontSize;
    const desktopDecimalSize = Math.round(mainFontSize.desktop * 0.6);
    const breakpointDecimalSize = Math.round(mainFontSize[breakpoint] * 0.6);

    if (breakpointDecimalSize !== desktopDecimalSize) {
      rules.push(`font-size: ${breakpointDecimalSize}px`);
    }
  }

  // Font weight responsive
  if (decimalTypo.fontWeight && isResponsiveValue(decimalTypo.fontWeight)) {
    const fontWeight = decimalTypo.fontWeight as ResponsiveValue<number>;
    if (fontWeight[breakpoint] !== fontWeight.desktop) {
      rules.push(`font-weight: ${fontWeight[breakpoint]}`);
    }
  }

  // Letter spacing responsive
  if (decimalTypo.letterSpacing && isResponsiveValue(decimalTypo.letterSpacing)) {
    const letterSpacing = decimalTypo.letterSpacing as ResponsiveValue<number>;
    if (letterSpacing[breakpoint] !== letterSpacing.desktop) {
      rules.push(`letter-spacing: ${letterSpacing[breakpoint]}px`);
    }
  }

  return rules;
}

/**
 * Generate line-through CSS if needed
 */
function generateLineThroughCSS(el: PriceElement): string {
  if (!el.lineThrough?.enabled) return "";

  const className = getClassName(el.type);
  const lt = el.lineThrough;

  // Only add position: relative if element is not already absolute
  // This allows pseudo-elements to work without breaking absolute positioning
  const positionRule = el.positionType === "absolute" ? "" : "position: relative;";

  // Cross style: X pattern using both ::before and ::after
  if (lt.style === "cross") {
    return `.${className}::before,
.${className}::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: ${lt.thickness}px;
  background-color: ${lt.color};
}

.${className}::before {
  transform: translateY(-50%) rotate(15deg);
}

.${className}::after {
  transform: translateY(-50%) rotate(-15deg);
}
${
  positionRule
    ? `
.${className} {
  ${positionRule}
}`
    : ""
}`;
  }

  // Single or double style
  // Convert direction to rotation angle
  let rotation = 0;
  if (lt.direction === "diagonal-down") {
    rotation = 15;
  } else if (lt.direction === "diagonal-up") {
    rotation = -15;
  }

  return `.${className}::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: ${lt.thickness}px;
  background-color: ${lt.color};
  transform: translateY(-50%)${rotation !== 0 ? ` rotate(${rotation}deg)` : ""};
  ${lt.style === "double" ? `box-shadow: 0 ${lt.thickness + 2}px 0 ${lt.color};` : ""}
}
${
  positionRule
    ? `
.${className} {
  ${positionRule}
}`
    : ""
}`;
}

/**
 * Generate CSS for variable price range element
 */
function generateVariablePriceRangeCSS(el: VariablePriceRangeElement): string {
  const className = "oppb-variable-range";
  const rules: string[] = [];

  // Main typography values for inheritance
  const mainFontSize = el.typography.fontSize.desktop;
  const mainFontWeight = el.typography.fontWeight.desktop;

  // Check if specific typography properties are explicitly set
  const hasSeparatorFontSize = el.separatorTypography?.fontSize !== undefined;
  const hasSeparatorFontWeight = el.separatorTypography?.fontWeight !== undefined;
  const hasMinFontSize = el.minPriceTypography?.fontSize !== undefined;
  const hasMinFontWeight = el.minPriceTypography?.fontWeight !== undefined;
  const hasMaxFontSize = el.maxPriceTypography?.fontSize !== undefined;
  const hasMaxFontWeight = el.maxPriceTypography?.fontWeight !== undefined;

  // Separator styles - inherit from main typography if not explicitly set
  const sepFontSize = hasSeparatorFontSize ? getDesktopValue(el.separatorTypography!.fontSize, mainFontSize * 0.75) : mainFontSize * 0.75;
  const sepFontWeight = hasSeparatorFontWeight ? getDesktopValue(el.separatorTypography!.fontWeight, mainFontWeight) : mainFontWeight;
  const sepLetterSpacing = getDesktopValue(el.separatorTypography?.letterSpacing, 4);
  rules.push(`.${className}__separator {
  font-size: ${sepFontSize}px;
  font-weight: ${sepFontWeight};
  padding: 0 ${sepLetterSpacing}px;
}`);

  // Prefix styles (for "From" / "Up to" text) - same as separator
  rules.push(`.${className}__prefix {
  font-size: ${sepFontSize}px;
  font-weight: ${sepFontWeight};
  margin-right: 4px;
}`);

  // Min price typography - inherit from main typography if not explicitly set
  const minFontSize = hasMinFontSize ? getDesktopValue(el.minPriceTypography!.fontSize, mainFontSize) : mainFontSize;
  const minFontWeight = hasMinFontWeight ? getDesktopValue(el.minPriceTypography!.fontWeight, mainFontWeight) : mainFontWeight;
  rules.push(`.${className}__min {
  font-size: ${minFontSize}px;
  font-weight: ${minFontWeight};
}`);

  // Min price inner elements - explicitly inherit to ensure consistent sizing
  rules.push(`.${className}__min-currency,
.${className}__min-main {
  font-size: inherit;
  font-weight: inherit;
}`);

  // Max price typography - inherit from main typography if not explicitly set
  const maxFontSize = hasMaxFontSize ? getDesktopValue(el.maxPriceTypography!.fontSize, mainFontSize) : mainFontSize;
  const maxFontWeight = hasMaxFontWeight ? getDesktopValue(el.maxPriceTypography!.fontWeight, mainFontWeight) : mainFontWeight;
  rules.push(`.${className}__max {
  font-size: ${maxFontSize}px;
  font-weight: ${maxFontWeight};
}`);

  // Max price inner elements - explicitly inherit to ensure consistent sizing
  rules.push(`.${className}__max-currency,
.${className}__max-main {
  font-size: inherit;
  font-weight: inherit;
}`);

  // Min price decimal
  if (el.minDecimal?.show && el.minDecimal.position !== "inline") {
    const decTypo = el.minDecimal.typography || {};
    const position = el.minDecimal.position;
    const decRules: string[] = [];

    if (position === "top") {
      decRules.push("vertical-align: top");
    } else if (position === "superscript") {
      decRules.push("vertical-align: super");
    } else if (position === "baseline") {
      decRules.push("vertical-align: baseline");
    }

    // Only use explicit decimal fontSize if set, otherwise scale with min price font
    const hasMinDecFontSize = decTypo.fontSize?.desktop !== undefined;
    const minDecFontSize = hasMinDecFontSize ? decTypo.fontSize!.desktop : Math.round(minFontSize * 0.6);
    const minDecFontWeight = getDesktopValue(decTypo.fontWeight, undefined);
    decRules.push(`font-size: ${minDecFontSize}px`);
    if (minDecFontWeight) decRules.push(`font-weight: ${minDecFontWeight}`);
    // Font style - explicitly set to prevent inheritance
    const minDecFontStyle = decTypo.fontStyle ?? "normal";
    decRules.push(`font-style: ${minDecFontStyle}`);
    // Letter spacing
    const minDecLetterSpacing = getDesktopValue(decTypo.letterSpacing, 0);
    if (minDecLetterSpacing !== 0) decRules.push(`letter-spacing: ${minDecLetterSpacing}px`);
    // Text decoration
    const minDecTextDecoration = decTypo.textDecoration ?? "none";
    if (minDecTextDecoration !== "none") decRules.push(`text-decoration: ${minDecTextDecoration}`);

    rules.push(`.${className}__min-decimal {
  ${decRules.join(";\n  ")};
}`);
  }

  // Max price decimal
  if (el.maxDecimal?.show && el.maxDecimal.position !== "inline") {
    const decTypo = el.maxDecimal.typography || {};
    const position = el.maxDecimal.position;
    const decRules: string[] = [];

    if (position === "top") {
      decRules.push("vertical-align: top");
    } else if (position === "superscript") {
      decRules.push("vertical-align: super");
    } else if (position === "baseline") {
      decRules.push("vertical-align: baseline");
    }

    // Only use explicit decimal fontSize if set, otherwise scale with max price font
    const hasMaxDecFontSize = decTypo.fontSize?.desktop !== undefined;
    const maxDecFontSize = hasMaxDecFontSize ? decTypo.fontSize!.desktop : Math.round(maxFontSize * 0.6);
    const maxDecFontWeight = getDesktopValue(decTypo.fontWeight, undefined);
    decRules.push(`font-size: ${maxDecFontSize}px`);
    if (maxDecFontWeight) decRules.push(`font-weight: ${maxDecFontWeight}`);
    // Font style - explicitly set to prevent inheritance
    const maxDecFontStyle = decTypo.fontStyle ?? "normal";
    decRules.push(`font-style: ${maxDecFontStyle}`);
    // Letter spacing
    const maxDecLetterSpacing = getDesktopValue(decTypo.letterSpacing, 0);
    if (maxDecLetterSpacing !== 0) decRules.push(`letter-spacing: ${maxDecLetterSpacing}px`);
    // Text decoration
    const maxDecTextDecoration = decTypo.textDecoration ?? "none";
    if (maxDecTextDecoration !== "none") decRules.push(`text-decoration: ${maxDecTextDecoration}`);

    rules.push(`.${className}__max-decimal {
  ${decRules.join(";\n  ")};
}`);
  }

  // Line-through for max price (for sale scenarios)
  if (el.lineThrough?.enabled) {
    const lt = el.lineThrough;
    rules.push(`.${className}__max {
  position: relative;
}

.${className}__max::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: ${lt.thickness || 2}px;
  background-color: ${lt.color || "#000"};
  transform: translateY(-50%);
}`);
  }

  return rules.join("\n\n");
}

/**
 * Generate responsive CSS rules for variable price range element
 * Returns a map of selectors to their responsive rules for the given breakpoint
 */
function generateResponsiveVariableRangeRules(el: VariablePriceRangeElement, breakpoint: "tablet" | "mobile"): Map<string, string[]> {
  const className = "oppb-variable-range";
  const result = new Map<string, string[]>();

  // Main typography values
  const mainFontSize = el.typography.fontSize;

  // Helper to check if responsive value differs from desktop
  const valuesDiffer = (value: ResponsiveValue<number> | undefined, bp: "tablet" | "mobile"): boolean => {
    if (!value) return false;
    return value[bp] !== value.desktop;
  };

  // Helper to get breakpoint value or fallback to desktop
  const getBpValue = (value: ResponsiveValue<number> | undefined, fallback: number): number => {
    if (!value) return fallback;
    return value[breakpoint];
  };

  // Separator responsive rules
  const hasSeparatorFontSize = el.separatorTypography?.fontSize !== undefined;
  if (hasSeparatorFontSize && valuesDiffer(el.separatorTypography!.fontSize, breakpoint)) {
    // Explicit separator font size that differs from desktop
    const sepFontSize = getBpValue(el.separatorTypography!.fontSize, mainFontSize[breakpoint] * 0.75);
    result.set(`.${className}__separator`, [`font-size: ${sepFontSize}px`]);
    result.set(`.${className}__prefix`, [`font-size: ${sepFontSize}px`]);
  } else if (valuesDiffer(mainFontSize, breakpoint)) {
    // Separator inherits from main (at 0.75 ratio), so if main differs, separator should too
    const sepFontSize = Math.round(mainFontSize[breakpoint] * 0.75);
    result.set(`.${className}__separator`, [`font-size: ${sepFontSize}px`]);
    result.set(`.${className}__prefix`, [`font-size: ${sepFontSize}px`]);
  }

  // Min price responsive rules
  const hasMinFontSize = el.minPriceTypography?.fontSize !== undefined;
  const minRules: string[] = [];
  let minFontSizeValue: number | null = null;
  if (hasMinFontSize && valuesDiffer(el.minPriceTypography!.fontSize, breakpoint)) {
    minFontSizeValue = getBpValue(el.minPriceTypography!.fontSize, mainFontSize[breakpoint]);
    minRules.push(`font-size: ${minFontSizeValue}px`);
  } else if (valuesDiffer(mainFontSize, breakpoint)) {
    // Min inherits from main, so if main differs, min should too
    minFontSizeValue = mainFontSize[breakpoint];
    minRules.push(`font-size: ${minFontSizeValue}px`);
  }
  if (minRules.length > 0) {
    result.set(`.${className}__min`, minRules);
    // Inner elements (__min-currency, __min-main) inherit font-size from __min
    // They don't need explicit font-size since they inherit from parent
  }

  // Max price responsive rules
  const hasMaxFontSize = el.maxPriceTypography?.fontSize !== undefined;
  const maxRules: string[] = [];
  let maxFontSizeValue: number | null = null;
  if (hasMaxFontSize && valuesDiffer(el.maxPriceTypography!.fontSize, breakpoint)) {
    maxFontSizeValue = getBpValue(el.maxPriceTypography!.fontSize, mainFontSize[breakpoint]);
    maxRules.push(`font-size: ${maxFontSizeValue}px`);
  } else if (valuesDiffer(mainFontSize, breakpoint)) {
    // Max inherits from main, so if main differs, max should too
    maxFontSizeValue = mainFontSize[breakpoint];
    maxRules.push(`font-size: ${maxFontSizeValue}px`);
  }
  if (maxRules.length > 0) {
    result.set(`.${className}__max`, maxRules);
    // Inner elements (__max-currency, __max-main) inherit font-size from __max
    // They don't need explicit font-size since they inherit from parent
  }

  // Min decimal responsive rules
  if (el.minDecimal?.show && el.minDecimal.position !== "inline") {
    const decTypo = el.minDecimal.typography || {};
    const minDecRules: string[] = [];

    // Calculate decimal font size for this breakpoint
    const hasExplicitFontSize = decTypo.fontSize !== undefined && isResponsiveValue(decTypo.fontSize);

    if (hasExplicitFontSize) {
      const fontSize = decTypo.fontSize as ResponsiveValue<number>;
      if (fontSize[breakpoint] !== fontSize.desktop) {
        minDecRules.push(`font-size: ${fontSize[breakpoint]}px`);
      }
    } else {
      // Scale proportionally from min price typography
      const minFontSizeVal = hasMinFontSize ? el.minPriceTypography!.fontSize : mainFontSize;
      if (minFontSizeVal && isResponsiveValue(minFontSizeVal)) {
        const desktopDecimalSize = Math.round(minFontSizeVal.desktop * 0.6);
        const breakpointDecimalSize = Math.round(minFontSizeVal[breakpoint] * 0.6);
        if (breakpointDecimalSize !== desktopDecimalSize) {
          minDecRules.push(`font-size: ${breakpointDecimalSize}px`);
        }
      }
    }

    if (minDecRules.length > 0) {
      result.set(`.${className}__min-decimal`, minDecRules);
    }
  }

  // Max decimal responsive rules
  if (el.maxDecimal?.show && el.maxDecimal.position !== "inline") {
    const decTypo = el.maxDecimal.typography || {};
    const maxDecRules: string[] = [];

    // Calculate decimal font size for this breakpoint
    const hasExplicitFontSize = decTypo.fontSize !== undefined && isResponsiveValue(decTypo.fontSize);

    if (hasExplicitFontSize) {
      const fontSize = decTypo.fontSize as ResponsiveValue<number>;
      if (fontSize[breakpoint] !== fontSize.desktop) {
        maxDecRules.push(`font-size: ${fontSize[breakpoint]}px`);
      }
    } else {
      // Scale proportionally from max price typography
      const maxFontSizeVal = hasMaxFontSize ? el.maxPriceTypography!.fontSize : mainFontSize;
      if (maxFontSizeVal && isResponsiveValue(maxFontSizeVal)) {
        const desktopDecimalSize = Math.round(maxFontSizeVal.desktop * 0.6);
        const breakpointDecimalSize = Math.round(maxFontSizeVal[breakpoint] * 0.6);
        if (breakpointDecimalSize !== desktopDecimalSize) {
          maxDecRules.push(`font-size: ${breakpointDecimalSize}px`);
        }
      }
    }

    if (maxDecRules.length > 0) {
      result.set(`.${className}__max-decimal`, maxDecRules);
    }
  }

  return result;
}

/**
 * Generate animation CSS if needed
 * Note: countUp animation is handled via JavaScript, not CSS
 */
function generateAnimationCSS(el: CanvasElement): string {
  // countUp uses JavaScript, not CSS animations
  if (el.animation.type === "none" || el.animation.type === "countUp") return "";

  const className = getClassName(el.type);
  const { duration, delay, easing } = el.animation;

  const keyframes: Record<string, string> = {
    fadeIn: `@keyframes oppb-fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}`,
    slideIn: `@keyframes oppb-slideIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}`,
    scaleIn: `@keyframes oppb-scaleIn {
  from { opacity: 0; transform: scale(0.9); }
  to { opacity: 1; transform: scale(1); }
}`,
    pulse: `@keyframes oppb-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}`,
    glow: `@keyframes oppb-glow {
  0%, 100% { box-shadow: 0 0 5px currentColor; }
  50% { box-shadow: 0 0 20px currentColor; }
}`,
  };

  const animationName = `oppb-${el.animation.type}`;
  const keyframe = keyframes[el.animation.type];

  if (!keyframe) return "";

  return `${keyframe}

.${className} {
  animation: ${animationName} ${duration}ms ${easing} ${delay}ms;
  ${
    el.animation.type === "pulse" || el.animation.type === "glow"
      ? "animation-iteration-count: infinite;"
      : "animation-fill-mode: forwards;"
  }
}`;
}

/**
 * Convert alignment type to CSS align-items value
 */
function alignmentToCSS(alignment: AlignmentInfo["vertical"]): string {
  switch (alignment) {
    case "baseline":
      return "baseline";
    case "center":
      return "center";
    case "flex-start":
      return "flex-start";
    case "flex-end":
      return "flex-end";
    case "custom":
      return "center"; // Default to center, we'll add individual adjustments
    default:
      return "baseline";
  }
}

/**
 * Generate responsive container spacing rules for a specific breakpoint
 */
function generateResponsiveContainerRules(
  containerSettings: ContainerSettings,
  breakpoint: "tablet" | "mobile",
  containerBounds?: ContainerBounds,
): string[] {
  const { padding, margin, border } = containerSettings;
  const rules: string[] = [];

  // Check padding differences
  const paddingTopDiff = padding.top[breakpoint] !== padding.top.desktop;
  const paddingRightDiff = padding.right[breakpoint] !== padding.right.desktop;
  const paddingBottomDiff = padding.bottom[breakpoint] !== padding.bottom.desktop;
  const paddingLeftDiff = padding.left[breakpoint] !== padding.left.desktop;

  if (paddingTopDiff || paddingRightDiff || paddingBottomDiff || paddingLeftDiff) {
    rules.push(
      `padding: ${padding.top[breakpoint]}px ${padding.right[breakpoint]}px ${padding.bottom[breakpoint]}px ${padding.left[breakpoint]}px`,
    );

    // Recalculate min dimensions if container bounds provided
    // The min dimensions should shrink proportionally with padding
    if (containerBounds) {
      const desktopPaddingH = padding.left.desktop + padding.right.desktop;
      const desktopPaddingV = padding.top.desktop + padding.bottom.desktop;
      const breakpointPaddingH = padding.left[breakpoint] + padding.right[breakpoint];
      const breakpointPaddingV = padding.top[breakpoint] + padding.bottom[breakpoint];

      // Calculate content size (bounds minus desktop padding)
      const contentWidth = containerBounds.width - desktopPaddingH;
      const contentHeight = containerBounds.height - desktopPaddingV;

      // New min dimensions = content + breakpoint padding
      const newMinWidth = Math.round(contentWidth + breakpointPaddingH);
      const newMinHeight = Math.round(contentHeight + breakpointPaddingV);

      rules.push(`--oppb-min-width: ${newMinWidth}px`);
      rules.push(`--oppb-min-height: ${newMinHeight}px`);
    }
  }

  // Check margin differences
  const marginTopDiff = margin.top[breakpoint] !== margin.top.desktop;
  const marginRightDiff = margin.right[breakpoint] !== margin.right.desktop;
  const marginBottomDiff = margin.bottom[breakpoint] !== margin.bottom.desktop;
  const marginLeftDiff = margin.left[breakpoint] !== margin.left.desktop;

  if (marginTopDiff || marginRightDiff || marginBottomDiff || marginLeftDiff) {
    rules.push(
      `margin: ${margin.top[breakpoint]}px ${margin.right[breakpoint]}px ${margin.bottom[breakpoint]}px ${margin.left[breakpoint]}px`,
    );
  }

  // Check border width differences
  if (border.width[breakpoint] !== border.width.desktop) {
    if (border.width[breakpoint] > 0) {
      rules.push(`border-width: ${border.width[breakpoint]}px`);
    } else {
      rules.push(`border-width: 0`);
    }
  }

  return rules;
}

/**
 * Generate all responsive CSS rules for an element
 */
function collectElementResponsiveRules(el: CanvasElement, breakpoint: "tablet" | "mobile"): string[] {
  const rules: string[] = [];

  // Typography
  rules.push(...generateResponsiveTypographyRules(el, breakpoint));

  // Border
  rules.push(...generateResponsiveBorderRules(el, breakpoint));

  // Padding
  rules.push(...generateResponsivePaddingRules(el, breakpoint));

  // Margin
  rules.push(...generateResponsiveMarginRules(el, breakpoint));

  return rules;
}

/**
 * Generate media query CSS block
 */
function generateMediaQueryCSS(tabletRules: Map<string, string[]>, mobileRules: Map<string, string[]>): string {
  const mediaQueries: string[] = [];

  // Tablet media query
  if (tabletRules.size > 0) {
    const tabletCSS: string[] = [];
    tabletRules.forEach((rules, selector) => {
      if (rules.length > 0) {
        tabletCSS.push(`  ${selector} {\n    ${rules.join(";\n    ")};\n  }`);
      }
    });

    if (tabletCSS.length > 0) {
      mediaQueries.push("");
      mediaQueries.push(`/* Tablet styles */`);
      mediaQueries.push(`@media (max-width: ${BREAKPOINTS.tablet}px) {`);
      mediaQueries.push(tabletCSS.join("\n\n"));
      mediaQueries.push(`}`);
    }
  }

  // Mobile media query
  if (mobileRules.size > 0) {
    const mobileCSS: string[] = [];
    mobileRules.forEach((rules, selector) => {
      if (rules.length > 0) {
        mobileCSS.push(`  ${selector} {\n    ${rules.join(";\n    ")};\n  }`);
      }
    });

    if (mobileCSS.length > 0) {
      mediaQueries.push("");
      mediaQueries.push(`/* Mobile styles */`);
      mediaQueries.push(`@media (max-width: ${BREAKPOINTS.mobile}px) {`);
      mediaQueries.push(mobileCSS.join("\n\n"));
      mediaQueries.push(`}`);
    }
  }

  return mediaQueries.join("\n");
}

/**
 * Generate CSS for container only (used in custom HTML mode)
 */
function generateContainerOnlyCSS(containerSettings: ContainerSettings): string {
  const cssRules: string[] = [`/* Opus Price Builder - Custom HTML Mode */`, ""];

  const containerCSSProps: string[] = ["position: relative", "display: inline-block"];

  const { padding, margin, border, backgroundColor, backgroundImage, backgroundSize, backgroundPosition, backgroundRepeat } =
    containerSettings;

  // Padding
  if (padding.top.desktop || padding.right.desktop || padding.bottom.desktop || padding.left.desktop) {
    containerCSSProps.push(
      `padding: ${padding.top.desktop}px ${padding.right.desktop}px ${padding.bottom.desktop}px ${padding.left.desktop}px`,
    );
  }

  // Margin
  if (margin.top.desktop || margin.right.desktop || margin.bottom.desktop || margin.left.desktop) {
    containerCSSProps.push(`margin: ${margin.top.desktop}px ${margin.right.desktop}px ${margin.bottom.desktop}px ${margin.left.desktop}px`);
  }

  // Border
  if (border.width.desktop > 0) {
    containerCSSProps.push(`border: ${border.width.desktop}px ${border.style} ${border.color}`);
  }

  if (border.radius > 0) {
    containerCSSProps.push(`border-radius: ${border.radius}px`);
  }

  // Background
  if (backgroundColor && backgroundColor !== "transparent") {
    containerCSSProps.push(`background-color: ${backgroundColor}`);
  }

  if (backgroundImage) {
    containerCSSProps.push(`background-image: url(${backgroundImage})`);
    containerCSSProps.push(`background-size: ${backgroundSize}`);
    containerCSSProps.push(`background-position: ${backgroundPosition}`);
    containerCSSProps.push(`background-repeat: ${backgroundRepeat}`);
  }

  cssRules.push(`.oppb-price-container {
  ${containerCSSProps.join(";\n  ")};
}`);

  // Generate responsive container rules
  const tabletRules = new Map<string, string[]>();
  const mobileRules = new Map<string, string[]>();

  const tabletContainerRules = generateResponsiveContainerRules(containerSettings, "tablet");
  const mobileContainerRules = generateResponsiveContainerRules(containerSettings, "mobile");

  if (tabletContainerRules.length > 0) {
    tabletRules.set(".oppb-price-container", tabletContainerRules);
  }
  if (mobileContainerRules.length > 0) {
    mobileRules.set(".oppb-price-container", mobileContainerRules);
  }

  // Add media queries
  const mediaQueryCSS = generateMediaQueryCSS(tabletRules, mobileRules);
  if (mediaQueryCSS) {
    cssRules.push(mediaQueryCSS);
  }

  // Add custom CSS if provided
  return cssRules.join("\n");
}

/**
 * Main export function - uses layout analyzer for smart CSS generation
 */
export function exportLayout(elements: CanvasElement[], containerSettings?: ContainerSettings): ExportResult {
  // Filter visible elements only
  const visibleElements = elements.filter((el) => el.visible);

  if (visibleElements.length === 0) {
    return {
      html: "<!-- No visible elements -->",
      css: "",
      webComponentHtml: "<!-- No visible elements -->",
    };
  }

  // Analyze layout
  const analysis = analyzeLayout(visibleElements);

  // Route to column or row layout generator
  if (analysis.layoutType === "columns" && analysis.columns.length >= 2) {
    return generateColumnLayout(analysis, visibleElements, containerSettings);
  }

  return generateRowLayout(analysis, visibleElements, containerSettings);
}

/**
 * Generate layout with column-based structure (e.g., currency on left, prices stacked on right)
 */
function generateColumnLayout(
  analysis: ReturnType<typeof analyzeLayout>,
  visibleElements: CanvasElement[],
  containerSettings?: ContainerSettings,
): ExportResult {
  const cssRules: string[] = [`/* Opus Price Builder - Generated CSS (Column Layout) */`, ""];

  // Container CSS - horizontal flex for columns
  const hasAbsolute = analysis.absoluteElements.length > 0;

  // Build container CSS properties
  const containerCSSProps: string[] = [
    "position: relative",
    "display: inline-flex",
    "flex-direction: row", // Horizontal for columns
    `align-items: ${analysis.containerAlignItems || "center"}`, // Vertical alignment of columns
    `gap: ${analysis.columnGap}px`, // Gap between columns
  ];

  // Add min dimensions for absolute elements
  if (hasAbsolute) {
    const minWidth = Math.round(analysis.containerBounds.width);
    const minHeight = Math.round(analysis.containerBounds.height);
    containerCSSProps.push(`--oppb-min-width: ${minWidth}px`);
    containerCSSProps.push(`--oppb-min-height: ${minHeight}px`);
    containerCSSProps.push(`min-width: var(--oppb-min-width)`);
    containerCSSProps.push(`min-height: var(--oppb-min-height)`);
  }

  // Add container settings if provided
  if (containerSettings) {
    const { padding, margin, border, backgroundColor, backgroundImage, backgroundSize, backgroundPosition, backgroundRepeat } =
      containerSettings;

    if (padding.top.desktop || padding.right.desktop || padding.bottom.desktop || padding.left.desktop) {
      containerCSSProps.push(
        `padding: ${padding.top.desktop}px ${padding.right.desktop}px ${padding.bottom.desktop}px ${padding.left.desktop}px`,
      );
    }

    if (margin.top.desktop || margin.right.desktop || margin.bottom.desktop || margin.left.desktop) {
      containerCSSProps.push(
        `margin: ${margin.top.desktop}px ${margin.right.desktop}px ${margin.bottom.desktop}px ${margin.left.desktop}px`,
      );
    }

    if (border.width.desktop > 0) {
      containerCSSProps.push(`border: ${border.width.desktop}px ${border.style} ${border.color}`);
    }

    if (border.radius > 0) {
      containerCSSProps.push(`border-radius: ${border.radius}px`);
    }

    if (backgroundColor && backgroundColor !== "transparent") {
      containerCSSProps.push(`background-color: ${backgroundColor}`);
    }

    if (backgroundImage) {
      containerCSSProps.push(`background-image: url(${backgroundImage})`);
      containerCSSProps.push(`background-size: ${backgroundSize}`);
      containerCSSProps.push(`background-position: ${backgroundPosition}`);
      containerCSSProps.push(`background-repeat: ${backgroundRepeat}`);
    }
  }

  cssRules.push(`.oppb-price-container {
  ${containerCSSProps.join(";\n  ")};
}`);

  // Generate column CSS
  analysis.columns.forEach((col, colIndex) => {
    const colClass = `.oppb-price-column--${colIndex + 1}`;

    // Determine column flex direction - if single element or elements on same Y, use flex-start
    const colCSSProps: string[] = [
      "display: inline-flex",
      "flex-direction: column", // Stack rows within column
      `align-items: flex-start`, // Align items to start within column
      `justify-content: ${col.verticalAlign}`, // Vertical alignment within column
    ];

    // Add row gap if column has multiple rows
    if (col.rows.length > 1) {
      colCSSProps.push(`gap: ${analysis.rowGap}px`);
    }

    cssRules.push("");
    cssRules.push(`${colClass} {
  ${colCSSProps.join(";\n  ")};
}`);

    // Generate row CSS within column
    col.rows.forEach((row, rowIndex) => {
      if (row.elements.length > 1 || col.rows.length > 1) {
        const rowClass = `${colClass} .oppb-price-row--${rowIndex + 1}`;
        const alignItems = alignmentToCSS(row.alignment.vertical);
        const justifyContent = row.alignment.horizontal || "flex-start";

        cssRules.push("");
        cssRules.push(`${rowClass} {
  display: inline-flex;
  align-items: ${alignItems};
  justify-content: ${justifyContent};
  gap: ${row.recommendedGap}px;
}`);

        // Handle custom vertical alignment offsets
        if (row.alignment.vertical === "custom") {
          row.alignment.offsets.forEach((offset, elementId) => {
            const el = row.elements.find((e) => e.id === elementId);
            if (el) {
              const className = getClassName(el.type);
              if (offset.top > 0) {
                cssRules.push(`${rowClass} .${className} { margin-top: ${offset.top}px; }`);
              } else if (offset.bottom > 0) {
                cssRules.push(`${rowClass} .${className} { margin-bottom: ${offset.bottom}px; }`);
              }
            }
          });
        }
      }
    });
  });

  // Generate CSS for each element
  visibleElements.forEach((el) => {
    const className = getClassName(el.type);
    const isAbsolute = el.positionType === "absolute";

    cssRules.push("");

    if (isAbsolute) {
      cssRules.push(`.${className} {
  ${generateAbsoluteCSS(el, analysis.containerBounds)};
  ${generateBaseElementCSS(el)};
}`);
    } else {
      cssRules.push(`.${className} {
  ${generateBaseElementCSS(el)};
}`);
    }

    // Add decimal CSS for price elements
    if (isPriceElement(el)) {
      const decimalCSS = generateDecimalCSS(el);
      if (decimalCSS) cssRules.push("", decimalCSS);

      const lineThroughCSS = generateLineThroughCSS(el);
      if (lineThroughCSS) cssRules.push("", lineThroughCSS);
    }

    // Add variable price range specific CSS
    if (isVariablePriceRangeElement(el)) {
      const variableRangeCSS = generateVariablePriceRangeCSS(el);
      if (variableRangeCSS) cssRules.push("", variableRangeCSS);
    }

    // Add multiline CSS for discount badges with custom format
    if (isDiscountBadgeElement(el) && el.format === "custom" && el.customFormat?.includes("\n")) {
      cssRules.push("");
      cssRules.push(`.${className} {
  display: flex;
  flex-direction: column;
  align-items: center;
}`);
      cssRules.push("");
      cssRules.push(`.oppb-discount-line {
  display: block;
}`);
    }

    // Add currency image CSS if applicable
    if (isCurrencyElement(el) && el.useCustomImage && el.customImageUrl) {
      cssRules.push("");
      cssRules.push(`.${className}__img {
  height: ${el.typography.fontSize.desktop}px;
  width: auto;
  display: block;
}`);
    }
  });

  // Responsive rules (similar to row layout)
  const tabletRules = new Map<string, string[]>();
  const mobileRules = new Map<string, string[]>();

  // Container responsive rules
  if (containerSettings) {
    const tabletContainerRules = generateResponsiveContainerRules(
      containerSettings,
      "tablet",
      hasAbsolute ? analysis.containerBounds : undefined,
    );
    const mobileContainerRules = generateResponsiveContainerRules(
      containerSettings,
      "mobile",
      hasAbsolute ? analysis.containerBounds : undefined,
    );

    if (tabletContainerRules.length > 0) {
      tabletRules.set(".oppb-price-container", tabletContainerRules);
    }
    if (mobileContainerRules.length > 0) {
      mobileRules.set(".oppb-price-container", mobileContainerRules);
    }
  }

  // Collect element responsive rules
  visibleElements.forEach((el) => {
    const className = `.${getClassName(el.type)}`;

    const tabletElementRules = collectElementResponsiveRules(el, "tablet");
    const mobileElementRules = collectElementResponsiveRules(el, "mobile");

    if (tabletElementRules.length > 0) {
      tabletRules.set(className, tabletElementRules);
    }
    if (mobileElementRules.length > 0) {
      mobileRules.set(className, mobileElementRules);
    }

    // Handle responsive decimal typography for price elements
    if (isPriceElement(el) && el.decimal?.show && el.decimal.position !== "inline") {
      const decimalSelector = `${className}__decimal`;

      const tabletDecimalRules = generateResponsiveDecimalRules(el, "tablet");
      const mobileDecimalRules = generateResponsiveDecimalRules(el, "mobile");

      if (tabletDecimalRules.length > 0) {
        tabletRules.set(decimalSelector, tabletDecimalRules);
      }
      if (mobileDecimalRules.length > 0) {
        mobileRules.set(decimalSelector, mobileDecimalRules);
      }
    }

    // Handle responsive rules for variable price range elements
    if (isVariablePriceRangeElement(el)) {
      const tabletVarRules = generateResponsiveVariableRangeRules(el, "tablet");
      const mobileVarRules = generateResponsiveVariableRangeRules(el, "mobile");

      tabletVarRules.forEach((rules, selector) => {
        const existing = tabletRules.get(selector) || [];
        tabletRules.set(selector, [...existing, ...rules]);
      });
      mobileVarRules.forEach((rules, selector) => {
        const existing = mobileRules.get(selector) || [];
        mobileRules.set(selector, [...existing, ...rules]);
      });
    }

    // Handle responsive font size for currency image
    if (isCurrencyElement(el) && el.useCustomImage && el.customImageUrl) {
      const imgSelector = `${className}__img`;

      if (el.typography.fontSize.tablet !== el.typography.fontSize.desktop) {
        const existingTablet = tabletRules.get(imgSelector) || [];
        existingTablet.push(`height: ${el.typography.fontSize.tablet}px`);
        tabletRules.set(imgSelector, existingTablet);
      }
      if (el.typography.fontSize.mobile !== el.typography.fontSize.desktop) {
        const existingMobile = mobileRules.get(imgSelector) || [];
        existingMobile.push(`height: ${el.typography.fontSize.mobile}px`);
        mobileRules.set(imgSelector, existingMobile);
      }
    }
  });

  // Add media queries
  const mediaQueryCSS = generateMediaQueryCSS(tabletRules, mobileRules);
  if (mediaQueryCSS) {
    cssRules.push(mediaQueryCSS);
  }

  // Add custom CSS
  // Generate HTML with column structure
  const htmlLines: string[] = [`<span class="oppb-price-container">`];
  const webComponentLines: string[] = [`<span class="oppb-price-container">`];

  analysis.columns.forEach((col, colIndex) => {
    const colClass = `oppb-price-column oppb-price-column--${colIndex + 1}`;
    htmlLines.push(`  <span class="${colClass}">`);
    webComponentLines.push(`  <span class="${colClass}">`);

    col.rows.forEach((row, rowIndex) => {
      if (row.elements.length > 1 || col.rows.length > 1) {
        // Wrap in row
        const rowClass = `oppb-price-row oppb-price-row--${rowIndex + 1}`;
        htmlLines.push(`    <span class="${rowClass}">`);
        webComponentLines.push(`    <span class="${rowClass}">`);

        row.elements.forEach((el) => {
          htmlLines.push(`      ${generateElementHTML(el, false)}`);
          webComponentLines.push(`      ${generateElementHTML(el, true)}`);
        });

        htmlLines.push(`    </span>`);
        webComponentLines.push(`    </span>`);
      } else if (row.elements.length === 1) {
        // Single element in single-row column - no row wrapper needed
        htmlLines.push(`    ${generateElementHTML(row.elements[0], false)}`);
        webComponentLines.push(`    ${generateElementHTML(row.elements[0], true)}`);
      }
    });

    htmlLines.push(`  </span>`);
    webComponentLines.push(`  </span>`);
  });

  // Add absolute positioned elements
  analysis.absoluteElements.forEach(({ element }) => {
    htmlLines.push(`  ${generateElementHTML(element, false)}`);
    webComponentLines.push(`  ${generateElementHTML(element, true)}`);
  });

  htmlLines.push(`</span>`);
  webComponentLines.push(`</span>`);


  return {
    html: htmlLines.join("\n"),
    css: cssRules.join("\n"),
    webComponentHtml: webComponentLines.join("\n"),
  };
}

/**
 * Generate traditional row-based layout
 */
function generateRowLayout(
  analysis: ReturnType<typeof analyzeLayout>,
  visibleElements: CanvasElement[],
  containerSettings?: ContainerSettings,
): ExportResult {
  // Generate CSS
  const cssRules: string[] = [`/* Opus Price Builder - Generated CSS */`, ""];

  // Container CSS - position relative for absolute children
  const hasAbsolute = analysis.absoluteElements.length > 0;

  // Determine the overall horizontal alignment for the container
  // If all rows have the same horizontal alignment, use that; otherwise default to flex-start
  let containerHorizontalAlign = "flex-start";
  if (analysis.rows.length > 0) {
    const rowAlignments = analysis.rows.map((r) => r.alignment.horizontal || "flex-start");
    const allSame = rowAlignments.every((a) => a === rowAlignments[0]);
    if (allSame) {
      containerHorizontalAlign = rowAlignments[0];
    }
  }

  // Build container CSS properties
  const containerCSSProps: string[] = [
    "position: relative",
    "display: inline-flex",
    "flex-direction: column",
    `align-items: ${containerHorizontalAlign}`,
    `gap: ${analysis.rowGap}px`,
  ];

  // Add min dimensions for absolute elements using CSS variables for responsiveness
  // Round to whole pixels for cleaner CSS output
  if (hasAbsolute) {
    const minWidth = Math.round(analysis.containerBounds.width);
    const minHeight = Math.round(analysis.containerBounds.height);
    containerCSSProps.push(`--oppb-min-width: ${minWidth}px`);
    containerCSSProps.push(`--oppb-min-height: ${minHeight}px`);
    containerCSSProps.push(`min-width: var(--oppb-min-width)`);
    containerCSSProps.push(`min-height: var(--oppb-min-height)`);
  }

  // Add container settings if provided
  if (containerSettings) {
    // Padding
    const { padding, margin, border, backgroundColor, backgroundImage, backgroundSize, backgroundPosition, backgroundRepeat } =
      containerSettings;

    if (padding.top.desktop || padding.right.desktop || padding.bottom.desktop || padding.left.desktop) {
      containerCSSProps.push(
        `padding: ${padding.top.desktop}px ${padding.right.desktop}px ${padding.bottom.desktop}px ${padding.left.desktop}px`,
      );
    }

    if (margin.top.desktop || margin.right.desktop || margin.bottom.desktop || margin.left.desktop) {
      containerCSSProps.push(
        `margin: ${margin.top.desktop}px ${margin.right.desktop}px ${margin.bottom.desktop}px ${margin.left.desktop}px`,
      );
    }

    // Border
    if (border.width.desktop > 0) {
      containerCSSProps.push(`border: ${border.width.desktop}px ${border.style} ${border.color}`);
    }

    if (border.radius > 0) {
      containerCSSProps.push(`border-radius: ${border.radius}px`);
    }

    // Background
    if (backgroundColor && backgroundColor !== "transparent") {
      containerCSSProps.push(`background-color: ${backgroundColor}`);
    }

    if (backgroundImage) {
      containerCSSProps.push(`background-image: url(${backgroundImage})`);
      containerCSSProps.push(`background-size: ${backgroundSize}`);
      containerCSSProps.push(`background-position: ${backgroundPosition}`);
      containerCSSProps.push(`background-repeat: ${backgroundRepeat}`);
    }
  }

  cssRules.push(`.oppb-price-container {
  ${containerCSSProps.join(";\n  ")};
}`);

  // Generate row CSS based on alignment analysis
  analysis.rows.forEach((row, rowIndex) => {
    const rowClass = analysis.rows.length > 1 ? `.oppb-price-row--${rowIndex + 1}` : ".oppb-price-row";
    const alignItems = alignmentToCSS(row.alignment.vertical);
    const justifyContent = row.alignment.horizontal || "flex-start";

    // For flex-end, center, or space-between, the row needs full width to take effect
    const needsFullWidth = justifyContent !== "flex-start";

    cssRules.push("");
    cssRules.push(`${rowClass} {
  display: inline-flex;
  align-items: ${alignItems};
  justify-content: ${justifyContent};${needsFullWidth ? "\n  width: 100%;" : ""}
  gap: ${row.recommendedGap}px;
}`);

    // If custom alignment, add individual element adjustments
    if (row.alignment.vertical === "custom") {
      row.alignment.offsets.forEach((offset, elementId) => {
        const el = row.elements.find((e) => e.id === elementId);
        if (el) {
          const className = getClassName(el.type);
          if (offset.top > 0) {
            cssRules.push("");
            cssRules.push(`/* Vertical offset for ${el.name} */`);
            cssRules.push(`${rowClass} .${className} { margin-top: ${offset.top}px; }`);
          } else if (offset.bottom > 0) {
            cssRules.push("");
            cssRules.push(`/* Vertical offset for ${el.name} */`);
            cssRules.push(`${rowClass} .${className} { margin-bottom: ${offset.bottom}px; }`);
          }
        }
      });
    }
  });

  // Generate CSS for each element
  visibleElements.forEach((el) => {
    const className = getClassName(el.type);
    const isAbsolute = el.positionType === "absolute";

    cssRules.push("");

    if (isAbsolute) {
      cssRules.push(`.${className} {
  ${generateAbsoluteCSS(el, analysis.containerBounds)};
  ${generateBaseElementCSS(el)};
}`);
    } else {
      cssRules.push(`.${className} {
  ${generateBaseElementCSS(el)};
}`);
    }

    // Add decimal CSS for price elements
    if (isPriceElement(el)) {
      const decimalCSS = generateDecimalCSS(el);
      if (decimalCSS) cssRules.push("", decimalCSS);

      const lineThroughCSS = generateLineThroughCSS(el);
      if (lineThroughCSS) cssRules.push("", lineThroughCSS);
    }

    // Add variable price range specific CSS
    if (isVariablePriceRangeElement(el)) {
      const variableRangeCSS = generateVariablePriceRangeCSS(el);
      if (variableRangeCSS) cssRules.push("", variableRangeCSS);
    }

    // Add multiline CSS for discount badges with custom format
    if (isDiscountBadgeElement(el) && el.format === "custom" && el.customFormat?.includes("\n")) {
      cssRules.push("");
      cssRules.push(`.${className} {
  display: flex;
  flex-direction: column;
  align-items: center;
}`);
      cssRules.push("");
      cssRules.push(`.oppb-discount-line {
  display: block;
}`);
    }

    // Add text element specific CSS
    if (isTextElement(el)) {
      const textRules: string[] = [];

      // Text alignment
      textRules.push(`text-align: ${el.textAlign}`);

      // Width mode handling
      if (el.widthMode === "full") {
        textRules.push("width: 100%");
      } else if (el.widthMode === "custom") {
        textRules.push(`width: ${el.customWidth}px`);
      }

      // White space for preserving line breaks
      textRules.push("white-space: pre-wrap");

      // Background image if set
      if (el.backgroundImage) {
        textRules.push(`background-image: url('${el.backgroundImage}')`);
        textRules.push(`background-size: ${el.backgroundSize}`);
        textRules.push(`background-position: ${el.backgroundPosition}`);
        textRules.push(`background-repeat: ${el.backgroundRepeat}`);
      }

      cssRules.push("");
      cssRules.push(`.${className} {
  ${textRules.join(";\n  ")};
}`);

      // Multiline text CSS
      if (el.text?.includes("\n")) {
        cssRules.push("");
        cssRules.push(`.oppb-text-line {
  display: block;
}`);
      }
    }

    // Add currency image CSS for currency elements
    if (isCurrencyElement(el) && el.useCustomImage && el.customImageUrl) {
      const className = getClassName(el.type);
      cssRules.push("");
      cssRules.push(`.${className}__img {
  height: ${el.typography.fontSize.desktop}px;
  width: auto;
  vertical-align: middle;
}`);
    }

    // Add animation CSS
    const animationCSS = generateAnimationCSS(el);
    if (animationCSS) cssRules.push("", animationCSS);
  });

  // ==========================================================================
  // Generate Responsive CSS (Media Queries)
  // ==========================================================================
  const tabletRules = new Map<string, string[]>();
  const mobileRules = new Map<string, string[]>();

  // Collect container responsive rules
  if (containerSettings) {
    const tabletContainerRules = generateResponsiveContainerRules(
      containerSettings,
      "tablet",
      hasAbsolute ? analysis.containerBounds : undefined,
    );
    const mobileContainerRules = generateResponsiveContainerRules(
      containerSettings,
      "mobile",
      hasAbsolute ? analysis.containerBounds : undefined,
    );

    if (tabletContainerRules.length > 0) {
      tabletRules.set(".oppb-price-container", tabletContainerRules);
    }
    if (mobileContainerRules.length > 0) {
      mobileRules.set(".oppb-price-container", mobileContainerRules);
    }
  }

  // Collect element responsive rules
  visibleElements.forEach((el) => {
    const className = `.${getClassName(el.type)}`;

    const tabletElementRules = collectElementResponsiveRules(el, "tablet");
    const mobileElementRules = collectElementResponsiveRules(el, "mobile");

    if (tabletElementRules.length > 0) {
      tabletRules.set(className, tabletElementRules);
    }
    if (mobileElementRules.length > 0) {
      mobileRules.set(className, mobileElementRules);
    }

    // Handle responsive decimal typography for price elements
    if (isPriceElement(el) && el.decimal?.show && el.decimal.position !== "inline") {
      const decimalSelector = `${className}__decimal`;

      const tabletDecimalRules = generateResponsiveDecimalRules(el, "tablet");
      const mobileDecimalRules = generateResponsiveDecimalRules(el, "mobile");

      if (tabletDecimalRules.length > 0) {
        tabletRules.set(decimalSelector, tabletDecimalRules);
      }
      if (mobileDecimalRules.length > 0) {
        mobileRules.set(decimalSelector, mobileDecimalRules);
      }
    }

    // Handle responsive rules for variable price range elements
    if (isVariablePriceRangeElement(el)) {
      const tabletVarRules = generateResponsiveVariableRangeRules(el, "tablet");
      const mobileVarRules = generateResponsiveVariableRangeRules(el, "mobile");

      // Merge into main maps
      tabletVarRules.forEach((rules, selector) => {
        const existing = tabletRules.get(selector) || [];
        tabletRules.set(selector, [...existing, ...rules]);
      });
      mobileVarRules.forEach((rules, selector) => {
        const existing = mobileRules.get(selector) || [];
        mobileRules.set(selector, [...existing, ...rules]);
      });
    }

    // Also handle responsive font size for currency image
    if (isCurrencyElement(el) && el.useCustomImage && el.customImageUrl) {
      const imgSelector = `${className}__img`;

      // Check if font size differs for tablet/mobile
      if (el.typography.fontSize.tablet !== el.typography.fontSize.desktop) {
        const existingTablet = tabletRules.get(imgSelector) || [];
        existingTablet.push(`height: ${el.typography.fontSize.tablet}px`);
        tabletRules.set(imgSelector, existingTablet);
      }
      if (el.typography.fontSize.mobile !== el.typography.fontSize.desktop) {
        const existingMobile = mobileRules.get(imgSelector) || [];
        existingMobile.push(`height: ${el.typography.fontSize.mobile}px`);
        mobileRules.set(imgSelector, existingMobile);
      }
    }
  });

  // Add media queries to CSS
  const mediaQueryCSS = generateMediaQueryCSS(tabletRules, mobileRules);
  if (mediaQueryCSS) {
    cssRules.push(mediaQueryCSS);
  }

  // Add custom CSS from container settings if provided
  // Generate HTML - using span elements for WooCommerce compatibility
  // WooCommerce wraps prices in <span class="price"> which cannot contain divs
  const htmlLines: string[] = [`<span class="oppb-price-container">`];
  const webComponentLines: string[] = [`<span class="oppb-price-container">`];

  // Generate rows
  analysis.rows.forEach((row, rowIndex) => {
    const rowClass = analysis.rows.length > 1 ? `oppb-price-row oppb-price-row--${rowIndex + 1}` : "oppb-price-row";

    if (row.elements.length > 1) {
      htmlLines.push(`  <span class="${rowClass}">`);
      webComponentLines.push(`  <span class="${rowClass}">`);

      row.elements.forEach((el) => {
        htmlLines.push(`    ${generateElementHTML(el, false)}`);
        webComponentLines.push(`    ${generateElementHTML(el, true)}`);
      });

      htmlLines.push(`  </span>`);
      webComponentLines.push(`  </span>`);
    } else if (row.elements.length === 1) {
      // Single element row - still wrap if part of multi-row layout
      if (analysis.rows.length > 1) {
        htmlLines.push(`  <span class="${rowClass}">`);
        webComponentLines.push(`  <span class="${rowClass}">`);
        htmlLines.push(`    ${generateElementHTML(row.elements[0], false)}`);
        webComponentLines.push(`    ${generateElementHTML(row.elements[0], true)}`);
        htmlLines.push(`  </span>`);
        webComponentLines.push(`  </span>`);
      } else {
        htmlLines.push(`  ${generateElementHTML(row.elements[0], false)}`);
        webComponentLines.push(`  ${generateElementHTML(row.elements[0], true)}`);
      }
    }
  });

  // Add absolute positioned elements
  analysis.absoluteElements.forEach(({ element }) => {
    htmlLines.push(`  ${generateElementHTML(element, false)}`);
    webComponentLines.push(`  ${generateElementHTML(element, true)}`);
  });

  htmlLines.push(`</span>`);
  webComponentLines.push(`</span>`);


  return {
    html: htmlLines.join("\n"),
    css: cssRules.join("\n"),
    webComponentHtml: webComponentLines.join("\n"),
  };
}

/** @deprecated Import from `@/utils/layoutExporter/placeholders` instead */
export { availablePlaceholders } from "./layoutExporter/placeholders";
