/**
 * VariablePriceRangeRenderer Component
 *
 * Renders variable price range elements with:
 * - Range mode: "$19.99 – $99.99"
 * - From mode: "From $19.99"
 * - Up-to mode: "Up to $99.99"
 * - Min-only mode: "$19.99"
 * - Max-only mode: "$99.99"
 * - Support for showing original range (for sale scenarios)
 * - Decimal settings for both min and max prices
 */

import { useEffect, useCallback, useMemo } from "react";
import { Group, Text, Line } from "react-konva";
import { useCanvasStore } from "@/stores/canvasStore";
import type { VariablePriceRangeElement, DecimalSettings } from "@/types";
import { getCanvasFontFamily } from "@/types";
import { useGoogleFonts } from "@/hooks/useGoogleFonts";

interface VariablePriceRangeRendererProps {
  element: VariablePriceRangeElement;
}

// Build Konva fontStyle string
const buildFontStyle = (fontWeight: number, fontStyle: "normal" | "italic"): string => {
  const parts: string[] = [];
  if (fontWeight >= 700) {
    parts.push("bold");
  } else if (fontWeight <= 300) {
    parts.push("300");
  }
  if (fontStyle === "italic") {
    parts.push("italic");
  }
  return parts.join(" ") || "normal";
};

// Mock price data for canvas preview
// Get WC separators from settings
const getWcDecimalSeparator = (): string => {
  return window.oppbAdmin?.currency?.decimal_separator || ".";
};

const MOCK_MIN_PRICE_VALUE = 19.99;
const MOCK_MAX_PRICE_VALUE = 99.99;
const MOCK_CURRENCY = "$";

// Computed mock prices using WC decimal separator for display
const getMockMinPrice = (): string => {
  const wcDecSep = getWcDecimalSeparator();
  return `19${wcDecSep}99`;
};
const getMockMaxPrice = (): string => {
  const wcDecSep = getWcDecimalSeparator();
  return `99${wcDecSep}99`;
};

// For backward compatibility
const MOCK_MIN_PRICE = getMockMinPrice();
const MOCK_MAX_PRICE = getMockMaxPrice();

// Get price parts based on decimal settings
// Uses WooCommerce separator settings for accurate preview
const getPriceParts = (
  price: string,
  decimalSettings: DecimalSettings | undefined
): { main: string; decimal: string; separator: string } => {
  const wcDecSep = getWcDecimalSeparator();
  const [main, dec] = price.split(wcDecSep);

  if (!decimalSettings?.show) {
    return { main, decimal: "", separator: "" };
  }

  // Use WC separator unless element explicitly overrides it
  let separator = wcDecSep;
  if (decimalSettings.separator === "comma") {
    separator = ",";
  } else if (decimalSettings.separator === "point") {
    separator = ".";
  } else if (decimalSettings.separator === "none") {
    separator = "";
  }

  return { main, decimal: dec || "", separator };
};

export function VariablePriceRangeRenderer({ element }: VariablePriceRangeRendererProps) {
  const updateElement = useCanvasStore((state) => state.updateElement);
  const padding = element.padding;
  const { displayMode, separator, prefixText, showCurrency } = element;

  // Collect all font families that need to be loaded
  const fontFamilies = useMemo(() => {
    const families: string[] = [
      element.typography.fontFamily,
      element.minPriceTypography?.fontFamily || "",
      element.maxPriceTypography?.fontFamily || "",
      element.separatorTypography?.fontFamily || "",
      element.minDecimal?.typography?.fontFamily || "",
      element.maxDecimal?.typography?.fontFamily || "",
    ].filter(Boolean);
    return families;
  }, [
    element.typography.fontFamily,
    element.minPriceTypography?.fontFamily,
    element.maxPriceTypography?.fontFamily,
    element.separatorTypography?.fontFamily,
    element.minDecimal?.typography?.fontFamily,
    element.maxDecimal?.typography?.fontFamily,
  ]);

  // Load all Google fonts - triggers re-render when any font is ready
  useGoogleFonts(fontFamilies);

  // Main typography values - this is the base that min/max inherit from
  const mainFontSize = element.typography.fontSize.desktop;
  const mainFontWeight = element.typography.fontWeight.desktop;
  const mainFontFamilyRaw = element.typography.fontFamily;
  const mainFontFamily = getCanvasFontFamily(mainFontFamilyRaw);
  const mainFontStyle = element.typography.fontStyle;

  // Min/max/separator font sizes - inherit from main typography if not explicitly overridden
  // Only use custom value if the typography object exists AND has fontSize explicitly set
  const minFontSize = element.minPriceTypography?.fontSize?.desktop ?? mainFontSize;
  const maxFontSize = element.maxPriceTypography?.fontSize?.desktop ?? mainFontSize;
  const separatorFontSize = element.separatorTypography?.fontSize?.desktop ?? Math.round(mainFontSize * 0.75);

  // Font weights - inherit from main if not explicitly set
  const minFontWeight = element.minPriceTypography?.fontWeight?.desktop ?? mainFontWeight;
  const maxFontWeight = element.maxPriceTypography?.fontWeight?.desktop ?? mainFontWeight;
  const separatorFontWeight = element.separatorTypography?.fontWeight?.desktop ?? 400;

  // Decimal font sizes - scale proportionally from min/max font sizes
  const minDecimalSize = element.minDecimal?.typography?.fontSize?.desktop ?? Math.round(minFontSize * 0.6);
  const maxDecimalSize = element.maxDecimal?.typography?.fontSize?.desktop ?? Math.round(maxFontSize * 0.6);

  /**
   * Calculate width of a single price with its decimal
   */
  const calculatePriceWidth = useCallback(
    (price: string, fontSize: number, decimalSettings: DecimalSettings | undefined, decFontSize: number, withCurrency: boolean): number => {
      const parts = getPriceParts(price, decimalSettings);
      const charWidth = fontSize * 0.6;
      const decCharWidth = decFontSize * 0.6;

      let width = withCurrency ? charWidth : 0; // currency
      width += parts.main.length * charWidth; // main price
      if (parts.decimal) {
        width += (parts.separator.length + parts.decimal.length) * decCharWidth;
      }
      return width;
    },
    []
  );

  /**
   * Calculate the total required width based on display mode and actual font sizes
   */
  const calculateRequiredWidth = useCallback(() => {
    const paddingH = padding.left.desktop + padding.right.desktop;

    switch (displayMode) {
      case "from": {
        const prefixWidth = (prefixText?.length ?? 0) * separatorFontSize * 0.6;
        const priceWidth = calculatePriceWidth(MOCK_MIN_PRICE, minFontSize, element.minDecimal, minDecimalSize, showCurrency);
        return prefixWidth + 8 + priceWidth + paddingH;
      }
      case "up-to": {
        const prefix = prefixText || "Up to";
        const prefixWidth = prefix.length * separatorFontSize * 0.6;
        const priceWidth = calculatePriceWidth(MOCK_MAX_PRICE, maxFontSize, element.maxDecimal, maxDecimalSize, showCurrency);
        return prefixWidth + 8 + priceWidth + paddingH;
      }
      case "min-only": {
        const priceWidth = calculatePriceWidth(MOCK_MIN_PRICE, minFontSize, element.minDecimal, minDecimalSize, showCurrency);
        return priceWidth + paddingH;
      }
      case "max-only": {
        const priceWidth = calculatePriceWidth(MOCK_MAX_PRICE, maxFontSize, element.maxDecimal, maxDecimalSize, showCurrency);
        return priceWidth + paddingH;
      }
      case "range":
      default: {
        const minWidth = calculatePriceWidth(MOCK_MIN_PRICE, minFontSize, element.minDecimal, minDecimalSize, showCurrency);
        const separatorWidth = (separator?.length ?? 3) * separatorFontSize * 0.6;
        const maxWidth = calculatePriceWidth(MOCK_MAX_PRICE, maxFontSize, element.maxDecimal, maxDecimalSize, showCurrency);
        return minWidth + separatorWidth + maxWidth + paddingH;
      }
    }
  }, [
    displayMode,
    separator,
    prefixText,
    showCurrency,
    padding,
    minFontSize,
    maxFontSize,
    separatorFontSize,
    minDecimalSize,
    maxDecimalSize,
    element.minDecimal,
    element.maxDecimal,
    calculatePriceWidth,
  ]);

  // Auto-resize element when typography or display mode changes
  useEffect(() => {
    // Calculate required height based on the largest font size used
    const maxUsedFontSize = Math.max(minFontSize, maxFontSize, separatorFontSize);
    const requiredHeight = maxUsedFontSize + padding.top.desktop + padding.bottom.desktop;
    const requiredWidth = calculateRequiredWidth();

    // Auto-resize to fit content (both grow and shrink)
    const widthDiffers = element.size.width !== Math.ceil(requiredWidth);
    const heightDiffers = element.size.height !== Math.ceil(requiredHeight);

    if (widthDiffers || heightDiffers) {
      updateElement(element.id, {
        size: {
          width: Math.ceil(requiredWidth),
          height: Math.ceil(requiredHeight),
        },
      });
    }
  }, [
    element.id,
    element.size.width,
    element.size.height,
    padding,
    minFontSize,
    maxFontSize,
    separatorFontSize,
    showCurrency,
    element.minDecimal?.show,
    element.maxDecimal?.show,
    calculateRequiredWidth,
    updateElement,
  ]);

  /**
   * Calculate decimal Y position based on position setting
   * Follows same logic as PriceElementRenderer
   */
  const calculateDecimalY = useCallback(
    (mainY: number, mainFontSz: number, decFontSz: number, decimalSettings: DecimalSettings | undefined): number => {
      const decimalPosition = decimalSettings?.position || "inline";

      // Font metrics
      const mainDescender = mainFontSz * 0.15;
      const decDescender = decFontSz * 0.15;
      const mainAscender = mainFontSz * 0.1;
      const decAscender = decFontSz * 0.1;

      if (decimalPosition === "baseline") {
        return mainY + (mainFontSz - mainDescender) - (decFontSz - decDescender);
      } else if (decimalPosition === "top") {
        return mainY + mainAscender - decAscender;
      } else if (decimalPosition === "superscript") {
        const mainBaseline = mainY + mainFontSz - mainDescender;
        const superscriptOffset = mainFontSz * 0.4;
        const decBaseline = mainBaseline - superscriptOffset;
        return decBaseline - (decFontSz - decDescender);
      } else if (decimalPosition === "absolute" && decimalSettings?.absoluteOffset) {
        return decimalSettings.absoluteOffset.y;
      }
      // inline: same Y as main
      const mainCenterY = mainY + mainFontSz / 2;
      return mainCenterY - decFontSz / 2;
    },
    []
  );

  /**
   * Calculate decimal X position for absolute mode
   */
  const calculateDecimalX = useCallback((baseX: number, decimalSettings: DecimalSettings | undefined): number => {
    if (decimalSettings?.position === "absolute" && decimalSettings?.absoluteOffset) {
      return decimalSettings.absoluteOffset.x;
    }
    return baseX;
  }, []);

  /**
   * Render a price with its decimal
   * Returns array of Text elements to be rendered
   */
  const renderPriceTexts = useCallback(
    (
      price: string,
      startX: number,
      mainY: number,
      fontSize: number,
      fontWeight: number,
      decimalSettings: DecimalSettings | undefined,
      decFontSize: number,
      withCurrency: boolean,
      keyPrefix: string
    ): JSX.Element[] => {
      const parts = getPriceParts(price, decimalSettings);
      const charWidth = fontSize * 0.6;
      const fontStyle = buildFontStyle(fontWeight, mainFontStyle);

      // Decimal typography
      const decFontWeight = decimalSettings?.typography?.fontWeight?.desktop ?? fontWeight;
      const decFontStyle = buildFontStyle(decFontWeight, (decimalSettings?.typography?.fontStyle as "normal" | "italic") ?? mainFontStyle);
      const decFontFamily = getCanvasFontFamily(decimalSettings?.typography?.fontFamily || "") ?? mainFontFamily;
      const decLetterSpacing = decimalSettings?.typography?.letterSpacing?.desktop ?? 0;
      const decTextDecoration = decimalSettings?.typography?.textDecoration ?? "none";

      const elements: JSX.Element[] = [];
      let currentX = startX;

      // Currency
      if (withCurrency) {
        elements.push(
          <Text
            key={`${keyPrefix}-currency`}
            x={currentX}
            y={mainY}
            text={MOCK_CURRENCY}
            fill={element.color}
            fontSize={fontSize}
            fontFamily={mainFontFamily}
            fontStyle={fontStyle}
          />
        );
        currentX += charWidth;
      }

      // Main price
      elements.push(
        <Text
          key={`${keyPrefix}-main`}
          x={currentX}
          y={mainY}
          text={parts.main}
          fill={element.color}
          fontSize={fontSize}
          fontFamily={mainFontFamily}
          fontStyle={fontStyle}
        />
      );
      currentX += parts.main.length * charWidth;

      // Decimal
      if (parts.decimal) {
        const decimalY = calculateDecimalY(mainY, fontSize, decFontSize, decimalSettings);
        const decimalX = calculateDecimalX(currentX, decimalSettings);

        elements.push(
          <Text
            key={`${keyPrefix}-decimal`}
            x={decimalX}
            y={decimalY}
            text={`${parts.separator}${parts.decimal}`}
            fill={element.color}
            fontSize={decFontSize}
            fontFamily={decFontFamily}
            fontStyle={decFontStyle}
            letterSpacing={decLetterSpacing}
            textDecoration={decTextDecoration === "none" ? "" : decTextDecoration}
          />
        );
      }

      return elements;
    },
    [element.color, mainFontFamily, mainFontStyle, calculateDecimalY, calculateDecimalX]
  );

  // Calculate main Y position (vertically centered)
  const contentHeight = element.size.height - padding.top.desktop - padding.bottom.desktop;
  const mainY = padding.top.desktop + Math.max(0, (contentHeight - mainFontSize) / 2);

  // Render based on display mode
  const renderContent = useCallback(() => {
    const paddingLeft = padding.left.desktop;
    const separatorStyle = buildFontStyle(separatorFontWeight, "normal");
    const separatorFamily = getCanvasFontFamily(element.separatorTypography?.fontFamily || "") ?? mainFontFamily;

    switch (displayMode) {
      case "from": {
        const prefixWidth = (prefixText?.length ?? 0) * separatorFontSize * 0.6;
        const prefixY = mainY + (mainFontSize - separatorFontSize) / 2;

        return (
          <Group listening={false}>
            {/* Prefix text */}
            <Text
              x={paddingLeft}
              y={prefixY}
              text={prefixText}
              fill={element.color}
              fontSize={separatorFontSize}
              fontFamily={separatorFamily}
              fontStyle={separatorStyle}
            />
            {/* Min price */}
            {renderPriceTexts(
              MOCK_MIN_PRICE,
              paddingLeft + prefixWidth + 8,
              mainY,
              minFontSize,
              minFontWeight,
              element.minDecimal,
              minDecimalSize,
              showCurrency,
              "min"
            )}
          </Group>
        );
      }

      case "up-to": {
        const upToPrefix = prefixText ?? "Up to";
        const prefixWidth = (upToPrefix.length ?? 0) * separatorFontSize * 0.6;
        const prefixY = mainY + (mainFontSize - separatorFontSize) / 2;

        return (
          <Group listening={false}>
            {/* Prefix text */}
            <Text
              x={paddingLeft}
              y={prefixY}
              text={upToPrefix}
              fill={element.color}
              fontSize={separatorFontSize}
              fontFamily={separatorFamily}
              fontStyle={separatorStyle}
            />
            {/* Max price */}
            {renderPriceTexts(
              MOCK_MAX_PRICE,
              paddingLeft + prefixWidth + 8,
              mainY,
              maxFontSize,
              maxFontWeight,
              element.maxDecimal,
              maxDecimalSize,
              showCurrency,
              "max"
            )}
          </Group>
        );
      }

      case "min-only":
        return (
          <Group listening={false}>
            {renderPriceTexts(
              MOCK_MIN_PRICE,
              paddingLeft,
              mainY,
              minFontSize,
              minFontWeight,
              element.minDecimal,
              minDecimalSize,
              showCurrency,
              "min"
            )}
          </Group>
        );

      case "max-only":
        return (
          <Group listening={false}>
            {renderPriceTexts(
              MOCK_MAX_PRICE,
              paddingLeft,
              mainY,
              maxFontSize,
              maxFontWeight,
              element.maxDecimal,
              maxDecimalSize,
              showCurrency,
              "max"
            )}
          </Group>
        );

      case "range":
      default: {
        const minPriceWidth = calculatePriceWidth(MOCK_MIN_PRICE, minFontSize, element.minDecimal, minDecimalSize, showCurrency);
        const separatorWidth = (separator?.length ?? 3) * separatorFontSize * 0.6;
        const separatorY = mainY + (mainFontSize - separatorFontSize) / 2;
        return (
          <Group listening={false}>
            {/* Min price */}
            {renderPriceTexts(
              MOCK_MIN_PRICE,
              paddingLeft,
              mainY,
              minFontSize,
              minFontWeight,
              element.minDecimal,
              minDecimalSize,
              showCurrency,
              "min"
            )}

            {/* Separator */}
            <Text
              x={paddingLeft + minPriceWidth}
              y={separatorY}
              text={separator}
              fill={element.color}
              fontSize={separatorFontSize}
              fontFamily={separatorFamily}
              fontStyle={separatorStyle}
            />

            {/* Max price */}
            {renderPriceTexts(
              MOCK_MAX_PRICE,
              paddingLeft + minPriceWidth + separatorWidth,
              mainY,
              maxFontSize,
              maxFontWeight,
              element.maxDecimal,
              maxDecimalSize,
              showCurrency,
              "max"
            )}
          </Group>
        );
      }
    }
  }, [
    displayMode,
    separator,
    prefixText,
    showCurrency,
    padding,
    mainY,
    mainFontSize,
    mainFontFamily,
    minFontSize,
    maxFontSize,
    separatorFontSize,
    minFontWeight,
    maxFontWeight,
    separatorFontWeight,
    minDecimalSize,
    maxDecimalSize,
    element.color,
    element.minDecimal,
    element.maxDecimal,
    element.separatorTypography?.fontFamily,
    renderPriceTexts,
    calculatePriceWidth,
  ]);

  // Render line-through if enabled (for original prices in sale mode)
  const renderLineThrough = useCallback(() => {
    if (!element.lineThrough?.enabled || !element.showOriginalRange) {
      return null;
    }

    const { color, thickness } = element.lineThrough;
    const paddingLeft = padding.left.desktop;

    // Calculate total content width
    let contentWidth = 0;
    if (displayMode === "range") {
      const minWidth = calculatePriceWidth(MOCK_MIN_PRICE, minFontSize, element.minDecimal, minDecimalSize, showCurrency);
      const sepWidth = (separator?.length ?? 3) * separatorFontSize * 0.6;
      const maxWidth = calculatePriceWidth(MOCK_MAX_PRICE, maxFontSize, element.maxDecimal, maxDecimalSize, showCurrency);
      contentWidth = minWidth + sepWidth + maxWidth;
    } else {
      const prefixWidth = (prefixText?.length ?? 0) * separatorFontSize * 0.6;
      const priceWidth = calculatePriceWidth(
        displayMode === "up-to" || displayMode === "max-only" ? MOCK_MAX_PRICE : MOCK_MIN_PRICE,
        displayMode === "up-to" || displayMode === "max-only" ? maxFontSize : minFontSize,
        displayMode === "up-to" || displayMode === "max-only" ? element.maxDecimal : element.minDecimal,
        displayMode === "up-to" || displayMode === "max-only" ? maxDecimalSize : minDecimalSize,
        showCurrency
      );
      contentWidth = displayMode === "min-only" || displayMode === "max-only" ? priceWidth : prefixWidth + 8 + priceWidth;
    }

    const lineY = mainY + mainFontSize / 2;

    return <Line points={[paddingLeft, lineY, paddingLeft + contentWidth, lineY]} stroke={color} strokeWidth={thickness} lineCap="round" />;
  }, [
    element.lineThrough,
    element.showOriginalRange,
    element.minDecimal,
    element.maxDecimal,
    padding,
    mainY,
    mainFontSize,
    minFontSize,
    maxFontSize,
    separatorFontSize,
    minDecimalSize,
    maxDecimalSize,
    displayMode,
    separator,
    prefixText,
    showCurrency,
    calculatePriceWidth,
  ]);

  return (
    <Group>
      {renderContent()}
      {renderLineThrough()}
    </Group>
  );
}

export default VariablePriceRangeRenderer;
