/**
 * PriceElementRenderer Component
 *
 * Renders price elements (regularPrice, salePrice) with:
 * - Currency symbol
 * - Main price
 * - Decimal with various alignment options
 * - Line-through support with direction options
 */

import { useEffect, useCallback } from "react";
import { Group, Text, Line } from "react-konva";
import { useCanvasStore } from "@/stores/canvasStore";
import { calculateElementSize } from "@/registry/elementFactory";
import type {
  PriceElement,
  LineThroughSettings,
  TypographySettings,
  ResponsiveTypographySettings,
  ResponsiveSpacing,
  ResponsiveValue,
} from "@/types";
import { isResponsiveValue, getCanvasFontFamily } from "@/types";
import { useGoogleFont } from "@/hooks/useGoogleFonts";

/**
 * Helper to get desktop value from a responsive or plain value
 */
const 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;
};

/**
 * Helper to extract desktop (flat) typography from responsive typography.
 * Used for size calculations that need non-responsive values.
 */
const getDesktopTypography = (typography: ResponsiveTypographySettings): TypographySettings => ({
  fontFamily: typography.fontFamily,
  fontSize: typography.fontSize.desktop,
  fontWeight: typography.fontWeight.desktop,
  fontStyle: typography.fontStyle,
  lineHeight: typography.lineHeight,
  letterSpacing: typography.letterSpacing.desktop,
  textTransform: typography.textTransform,
  textDecoration: typography.textDecoration,
});

/**
 * Helper to extract desktop (flat) padding from responsive padding.
 */
const getDesktopPadding = (padding: ResponsiveSpacing): { top: number; right: number; bottom: number; left: number } => ({
  top: padding.top.desktop,
  right: padding.right.desktop,
  bottom: padding.bottom.desktop,
  left: padding.left.desktop,
});

interface PriceElementRendererProps {
  element: PriceElement;
}

// Build Konva fontStyle string for decimal text
const buildDecimalFontStyle = (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";
};

// Build Konva fontStyle string
const buildFontStyle = (element: PriceElement): string => {
  const parts: string[] = [];

  if (element.typography.fontWeight.desktop >= 700) {
    parts.push("bold");
  } else if (element.typography.fontWeight.desktop <= 300) {
    parts.push("300");
  }

  if (element.typography.fontStyle === "italic") {
    parts.push("italic");
  }

  return parts.join(" ") || "normal";
};

// Get WC decimal separator from settings
const getWcDecimalSeparator = (): string => {
  return window.oppbAdmin?.currency?.decimal_separator || ".";
};

// Get price parts based on element type and settings
// Uses WooCommerce decimal separator setting for accurate preview
const getPriceParts = (element: PriceElement): { main: string; decimal: string; separator: string } => {
  // Sample prices use WC decimal separator for realistic preview
  const wcDecSep = getWcDecimalSeparator();
  const fullPrice = element.type === "regularPrice" ? `99${wcDecSep}99` : `79${wcDecSep}99`;
  const [main, dec] = fullPrice.split(wcDecSep);

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

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

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

// Calculate proportional decimal size
// Only use explicit decimal fontSize if set, otherwise scale proportionally with main font
const getProportionalDecimalSize = (element: PriceElement): number => {
  const decFontSize = element.decimal?.typography?.fontSize;
  // Check if fontSize is explicitly set (has a desktop value)
  const hasExplicitFontSize = decFontSize?.desktop !== undefined;

  if (hasExplicitFontSize) {
    return decFontSize.desktop;
  }
  // Default: 60% of main font size
  return Math.round(element.typography.fontSize.desktop * 0.6);
};

export function PriceElementRenderer({ element }: PriceElementRendererProps) {
  const updateElement = useCanvasStore((state) => state.updateElement);
  const padding = element.padding;
  const priceParts = getPriceParts(element);

  // Load Google fonts if needed - triggers re-render when font is ready
  useGoogleFont(element.typography.fontFamily);
  useGoogleFont(element.decimal?.typography?.fontFamily || "");

  // Get canvas-safe font family (undefined for default, actual value otherwise)
  const mainFontFamily = getCanvasFontFamily(element.typography.fontFamily);

  // Get decimal typography
  const getDecimalTypography = useCallback(() => {
    if (element.decimal?.position === "inline") {
      return {
        fontSize: element.typography.fontSize.desktop,
        fontWeight: element.typography.fontWeight.desktop,
        fontFamily: mainFontFamily,
        fontStyle: element.typography.fontStyle,
        letterSpacing: element.typography.letterSpacing.desktop,
        textDecoration: element.typography.textDecoration,
      };
    }

    const proportionalSize = getProportionalDecimalSize(element);
    const decimalFontFamily = getCanvasFontFamily(element.decimal?.typography?.fontFamily || "") ?? mainFontFamily;
    return {
      fontSize: proportionalSize,
      fontWeight: getDesktopValue(element.decimal?.typography?.fontWeight, element.typography.fontWeight.desktop),
      fontFamily: decimalFontFamily,
      fontStyle: element.decimal?.typography?.fontStyle ?? element.typography.fontStyle,
      letterSpacing: getDesktopValue(element.decimal?.typography?.letterSpacing, element.typography.letterSpacing.desktop),
      textDecoration: element.decimal?.typography?.textDecoration ?? "none",
    };
  }, [element, mainFontFamily]);

  const decimalTypo = getDecimalTypography();

  // Auto-resize element when typography or padding changes
  useEffect(() => {
    const priceText = element.type === "regularPrice" ? "$99.99" : "$79.99";
    const decFontSize = decimalTypo.fontSize;
    const showCurrency = element.decimal?.showCurrency ?? true;
    const showDecimals = element.decimal?.show ?? true;

    const requiredSize = calculateElementSize(
      priceText,
      getDesktopTypography(element.typography),
      getDesktopPadding(element.padding),
      showDecimals,
      decFontSize,
      showCurrency
    );

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

    if (widthDiffers || heightDiffers) {
      updateElement(element.id, {
        size: {
          width: requiredSize.width,
          height: requiredSize.height,
        },
      });
    }
  }, [
    element.id,
    element.type,
    element.size.width,
    element.size.height,
    element.typography,
    element.padding,
    element.decimal?.show,
    element.decimal?.showCurrency,
    decimalTypo.fontSize,
    updateElement,
  ]);

  // Calculate layout positions
  const calculatePriceLayout = useCallback(() => {
    const mainFontSize = element.typography.fontSize.desktop;
    const decFontSize = decimalTypo.fontSize;
    const showCurrency = element.decimal?.showCurrency ?? true;
    const decimalPosition = element.decimal?.position || "inline";

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

    // Font metrics
    const mainDescender = mainFontSize * 0.15;
    const decDescender = decFontSize * 0.15;
    const mainAscender = mainFontSize * 0.1;
    const decAscender = decFontSize * 0.1;

    let decimalY: number;

    if (decimalPosition === "baseline") {
      decimalY = mainY + (mainFontSize - mainDescender) - (decFontSize - decDescender);
    } else if (decimalPosition === "top") {
      decimalY = mainY + mainAscender - decAscender;
    } else if (decimalPosition === "superscript") {
      const mainBaseline = mainY + mainFontSize - mainDescender;
      const superscriptOffset = mainFontSize * 0.4;
      const decBaseline = mainBaseline - superscriptOffset;
      decimalY = decBaseline - (decFontSize - decDescender);
    } else {
      const mainCenterY = mainY + mainFontSize / 2;
      decimalY = mainCenterY - decFontSize / 2;
    }

    const currencyWidth = showCurrency ? mainFontSize * 0.6 : 0;
    const mainWidth = mainFontSize * priceParts.main.length * 0.6;

    const isAbsolute = decimalPosition === "absolute";
    const absoluteX = element.decimal?.absoluteOffset?.x ?? 0;
    const absoluteY = element.decimal?.absoluteOffset?.y ?? 0;

    return {
      currency: {
        x: padding.left.desktop,
        y: mainY,
        visible: showCurrency,
      },
      main: {
        x: padding.left.desktop + currencyWidth,
        y: mainY,
      },
      decimal: {
        x: isAbsolute ? absoluteX : padding.left.desktop + currencyWidth + mainWidth,
        y: isAbsolute ? absoluteY : decimalY,
      },
    };
  }, [element, decimalTypo, padding, priceParts.main.length]);

  const priceLayout = calculatePriceLayout();

  return (
    <Group listening={false}>
      {/* Currency symbol */}
      {priceLayout.currency.visible && (
        <Text
          x={priceLayout.currency.x}
          y={priceLayout.currency.y}
          text="$"
          fill={element.color}
          fontFamily={mainFontFamily}
          fontSize={element.typography.fontSize.desktop}
          fontStyle={buildFontStyle(element)}
          textDecoration={element.typography.textDecoration === "none" ? "" : element.typography.textDecoration}
        />
      )}

      {/* Main price */}
      <Text
        x={priceLayout.main.x}
        y={priceLayout.main.y}
        text={priceParts.main}
        fill={element.color}
        fontFamily={mainFontFamily}
        fontSize={element.typography.fontSize.desktop}
        fontStyle={buildFontStyle(element)}
        letterSpacing={element.typography.letterSpacing.desktop}
        textDecoration={element.typography.textDecoration === "none" ? "" : element.typography.textDecoration}
      />

      {/* Decimal */}
      {priceParts.decimal && (
        <Text
          x={priceLayout.decimal.x}
          y={priceLayout.decimal.y}
          text={`${priceParts.separator}${priceParts.decimal}`}
          fill={element.color}
          fontFamily={decimalTypo.fontFamily}
          fontSize={decimalTypo.fontSize}
          fontStyle={buildDecimalFontStyle(decimalTypo.fontWeight, decimalTypo.fontStyle)}
          letterSpacing={decimalTypo.letterSpacing}
          textDecoration={
            (element.decimal?.typography?.textDecoration ?? "none") === "none" ? "" : element.decimal?.typography?.textDecoration
          }
        />
      )}

      {/* Line-through for price */}
      {element.lineThrough?.enabled && (
        <LineThroughEffect element={element} paddingLeft={padding.left.desktop} paddingRight={padding.right.desktop} />
      )}
    </Group>
  );
}

/**
 * LineThroughEffect - Renders the line-through based on style and direction settings
 */
function LineThroughEffect({ element, paddingLeft, paddingRight }: { element: PriceElement; paddingLeft: number; paddingRight: number }) {
  const lineThrough = element.lineThrough as LineThroughSettings;
  const totalPaddingX = paddingLeft + paddingRight;
  const lineWidth = element.size.width - totalPaddingX;
  const centerY = element.size.height / 2;
  const inset = lineWidth * 0.05; // 5% inset from edges for diagonal lines

  // Calculate line points based on direction
  const getLinePoints = (direction: "horizontal" | "diagonal-down" | "diagonal-up", offsetY = 0): number[] => {
    switch (direction) {
      case "diagonal-down":
        // Top-left to bottom-right
        return [
          paddingLeft + inset,
          centerY - element.size.height * 0.2 + offsetY,
          paddingLeft + lineWidth - inset,
          centerY + element.size.height * 0.2 + offsetY,
        ];
      case "diagonal-up":
        // Bottom-left to top-right
        return [
          paddingLeft + inset,
          centerY + element.size.height * 0.2 + offsetY,
          paddingLeft + lineWidth - inset,
          centerY - element.size.height * 0.2 + offsetY,
        ];
      default:
        // Horizontal
        return [paddingLeft, centerY + offsetY, paddingLeft + lineWidth, centerY + offsetY];
    }
  };

  // Cross style renders both diagonal-down and diagonal-up
  if (lineThrough.style === "cross") {
    return (
      <Group listening={false}>
        <Line points={getLinePoints("diagonal-down")} stroke={lineThrough.color} strokeWidth={lineThrough.thickness} lineCap="round" />
        <Line points={getLinePoints("diagonal-up")} stroke={lineThrough.color} strokeWidth={lineThrough.thickness} lineCap="round" />
      </Group>
    );
  }

  // Single or double style
  const direction = lineThrough.direction || "horizontal";
  return (
    <Group listening={false}>
      <Line points={getLinePoints(direction)} stroke={lineThrough.color} strokeWidth={lineThrough.thickness} lineCap="round" />
      {lineThrough.style === "double" && (
        <Line points={getLinePoints(direction, 4)} stroke={lineThrough.color} strokeWidth={lineThrough.thickness} lineCap="round" />
      )}
    </Group>
  );
}
