import { jsxs, jsx } from 'react/jsx-runtime';
import { useState, useEffect, useRef, useMemo } from 'react';
import { useReducedMotion, motion } from 'motion/react';
import { cn } from '../../../utils/cn.js';
import { useTooltipPosition } from '../hooks/useTooltipPosition.js';
import { useChartAccessibility } from '../hooks/useChartAccessibility.js';
import { useChartValidation } from '../hooks/useChartValidation.js';
import { ChartErrorBoundary } from '../shared/ChartErrorBoundary/ChartErrorBoundary.js';
import { XAxis } from '../shared/ChartAxis/XAxis.js';
import { YAxis } from '../shared/ChartAxis/YAxis.js';
import { HorizontalGrid } from '../shared/ChartGrid/HorizontalGrid.js';
import { ChartTooltip } from '../shared/ChartTooltip/ChartTooltip.js';
import { STACKED_BAR_CHART_DEFAULTS } from './StackedBarChart.types.js';
import { ExclamationTriangleIcon } from '@heroicons/react/20/solid';

// Pure helper functions moved to module level to avoid recreation per render
const createRoundedTopBarPath = (x, y, width, height, radius) => {
    const r = Math.min(radius, width / 2, height / 2);
    return `
    M ${x},${y + height}
    L ${x},${y + r}
    Q ${x},${y} ${x + r},${y}
    L ${x + width - r},${y}
    Q ${x + width},${y} ${x + width},${y + r}
    L ${x + width},${y + height}
    Z
  `.trim();
};
const createRectPath = (x, y, width, height) => {
    return `
    M ${x},${y + height}
    L ${x},${y}
    L ${x + width},${y}
    L ${x + width},${y + height}
    Z
  `.trim();
};
const StackedBarChart = ({ data, config, 
// Standardized display props with defaults
showGrid = STACKED_BAR_CHART_DEFAULTS.showGrid, showXAxis = STACKED_BAR_CHART_DEFAULTS.showXAxis, showYAxis = STACKED_BAR_CHART_DEFAULTS.showYAxis, minValue: propMinValue, maxValue: propMaxValue, variant = STACKED_BAR_CHART_DEFAULTS.variant, theme, 
// Bar visual props
barRadius = STACKED_BAR_CHART_DEFAULTS.barRadius, categoryGap = STACKED_BAR_CHART_DEFAULTS.categoryGap, 
// Stacking behavior
stackOffset = STACKED_BAR_CHART_DEFAULTS.stackOffset, 
// Animation props
showAnimation = STACKED_BAR_CHART_DEFAULTS.showAnimation, 
// Base props
className, title, description, enableKeyboardNavigation = STACKED_BAR_CHART_DEFAULTS.enableKeyboardNavigation, showValidationWarnings = process.env.NODE_ENV === "development", children, ...props }) => {
    var _a;
    // Animation state
    const shouldReduceMotion = useReducedMotion();
    const [hasAnimated, setHasAnimated] = useState(false);
    useEffect(() => {
        if (!shouldReduceMotion && showAnimation) {
            setHasAnimated(true);
        }
        else {
            setHasAnimated(true);
        }
    }, [shouldReduceMotion, showAnimation]);
    // Validate data and config with error handling
    const { validation, sanitizedData, isValid, hasWarnings, safeScale, safeMath, } = useChartValidation(data, config, {
        autoSanitize: true,
        logWarnings: true,
    });
    // Early return for invalid data
    if (!isValid) {
        return (jsxs("div", { className: cn("chart-container flex flex-col items-center justify-center p-6 border border-border rounded-lg text-2xl", className), role: "alert", "aria-live": "polite", ...props, children: [jsxs("div", { className: "flex flex-col items-center gap-4 mb-1", children: [jsx(ExclamationTriangleIcon, { className: "size-6 text-[var(--color-danger)]" }), jsx("div", { className: "text-base font-semibold text-[var(--color-text-secondary)]", children: "Invalid Chart Data" })] }), jsx("p", { className: "text-base text-[var(--color-text-secondary)]/70 mb-2", children: ((_a = validation.errors[0]) === null || _a === void 0 ? void 0 : _a.message) ||
                        "Unable to render chart due to data validation errors" })] }));
    }
    // Early return for empty data
    if (!sanitizedData || sanitizedData.length === 0) {
        return (jsx("div", { className: cn("chart-container flex items-center justify-center text-[var(--color-text-muted)]", className), role: "img", "aria-label": "Empty stacked bar chart", ...props, children: jsx("span", { children: "No data available" }) }));
    }
    // Color palette using CSS variables
    const getSeriesFillColor = (index) => {
        const colorVars = [
            "var(--color-primary)",
            "var(--color-primary-400)",
            "var(--color-primary-300)",
            "var(--color-primary-200)",
            "var(--color-warning)",
            "var(--color-success)",
        ];
        return colorVars[index % colorVars.length];
    };
    const containerRef = useRef(null);
    const [dimensions, setDimensions] = useState({ width: 600, height: 400 });
    const [hoveredCategory, setHoveredCategory] = useState(null);
    const isMobile = typeof window !== "undefined" &&
        ("ontouchstart" in window || navigator.maxTouchPoints > 0);
    const { tooltipData, tooltipRef, handleMouseEnter, handleMouseMove, handleMouseLeave, } = useTooltipPosition({
        containerRef,
        isMobile,
    });
    const { chartAccessibilityProps, descriptionProps, focusedElementIndex, isKeyboardMode, handleMouseInteraction, } = useChartAccessibility({
        chartType: "bar",
        data: sanitizedData,
        config,
        title,
        description,
        enableKeyboardNavigation,
    });
    // Measure container dimensions
    useEffect(() => {
        const updateDimensions = () => {
            if (containerRef.current) {
                const { width, height } = containerRef.current.getBoundingClientRect();
                setDimensions({
                    width: width || 600,
                    height: height || 400,
                });
            }
        };
        updateDimensions();
        const resizeObserver = new ResizeObserver(updateDimensions);
        if (containerRef.current) {
            resizeObserver.observe(containerRef.current);
        }
        return () => {
            resizeObserver.disconnect();
        };
    }, []);
    // Calculate dimensions
    const margin = useMemo(() => ({
        top: 15,
        right: showYAxis ? 20 : 0,
        bottom: showXAxis ? 20 : 0,
        left: showYAxis ? 60 : 0,
    }), [showYAxis, showXAxis]);
    const innerWidth = Math.max(0, dimensions.width - margin.left - margin.right);
    const innerHeight = Math.max(0, dimensions.height - margin.top - margin.bottom);
    // Get all data keys from config
    const dataKeys = useMemo(() => Object.keys(config || {}), [config]);
    // Animation timing
    const BAR_STAGGER = 0.08;
    // Calculate stacked values for each data point
    const getStackedValues = useMemo(() => {
        const stackedData = {};
        sanitizedData.forEach((item, dataIndex) => {
            let cumulativeValue = 0;
            dataKeys.forEach((key) => {
                if (!stackedData[key]) {
                    stackedData[key] = [];
                }
                const rawValue = item[key];
                const value = typeof rawValue === "number" && isFinite(rawValue) ? rawValue : 0;
                stackedData[key][dataIndex] = {
                    base: cumulativeValue,
                    top: cumulativeValue + value,
                };
                cumulativeValue += value;
            });
        });
        return stackedData;
    }, [sanitizedData, dataKeys]);
    // Calculate max stacked value for scale
    const maxStackedValue = useMemo(() => {
        let max = 0;
        sanitizedData.forEach((item) => {
            let sum = 0;
            dataKeys.forEach((key) => {
                const rawValue = item[key];
                const value = typeof rawValue === "number" && isFinite(rawValue) ? rawValue : 0;
                sum += value;
            });
            if (sum > max)
                max = sum;
        });
        return max;
    }, [sanitizedData, dataKeys]);
    // Apply stackOffset if needed
    const getScaledMaxValue = () => {
        if (stackOffset === "expand") {
            return 100; // Normalize to 100%
        }
        return propMaxValue !== null && propMaxValue !== void 0 ? propMaxValue : maxStackedValue;
    };
    const minValue = propMinValue !== null && propMinValue !== void 0 ? propMinValue : 0;
    const maxValue = getScaledMaxValue();
    // Safe bar width calculations
    const totalCategoryGap = Math.max(0, (sanitizedData.length - 1) * categoryGap);
    const availableWidth = Math.max(0, innerWidth - totalCategoryGap);
    const barWidth = safeMath.divide(availableWidth, sanitizedData.length, 0);
    // Render stacked bars
    const renderStackedBar = (item, categoryIndex, x) => {
        const isHovered = hoveredCategory === categoryIndex;
        const isAnyBarHovered = hoveredCategory !== null;
        const shouldReduceOpacity = isAnyBarHovered && !isHovered;
        const isFocused = isKeyboardMode && focusedElementIndex === categoryIndex;
        const range = maxValue - minValue;
        return (jsx("g", { children: dataKeys.map((key, keyIndex) => {
                var _a, _b;
                const stackData = (_a = getStackedValues[key]) === null || _a === void 0 ? void 0 : _a[categoryIndex];
                if (!stackData)
                    return null;
                let baseValue = stackData.base;
                let topValue = stackData.top;
                // Apply expand offset (normalize to percentage)
                if (stackOffset === "expand") {
                    const totalForCategory = dataKeys.reduce((sum, k) => {
                        const rawVal = item[k];
                        return (sum +
                            (typeof rawVal === "number" && isFinite(rawVal) ? rawVal : 0));
                    }, 0);
                    if (totalForCategory > 0) {
                        baseValue = (stackData.base / totalForCategory) * 100;
                        topValue = (stackData.top / totalForCategory) * 100;
                    }
                }
                const barHeight = range > 0
                    ? safeMath.scale(topValue - baseValue, 0, range, 0, innerHeight)
                    : 0;
                const barY = margin.top +
                    innerHeight -
                    safeMath.scale(topValue, minValue, maxValue, 0, innerHeight);
                const isTopSegment = keyIndex === dataKeys.length - 1;
                const pathD = isTopSegment
                    ? createRoundedTopBarPath(x, barY, barWidth, barHeight, barRadius)
                    : createRectPath(x, barY, barWidth, barHeight);
                const fillColor = ((_b = config[key]) === null || _b === void 0 ? void 0 : _b.color) || getSeriesFillColor(keyIndex);
                const delay = categoryIndex * BAR_STAGGER;
                return (jsx(motion.path, { d: pathD, initial: showAnimation && !shouldReduceMotion
                        ? { scaleY: 0, opacity: 0 }
                        : { scaleY: 1, opacity: 1 }, animate: {
                        scaleY: 1,
                        opacity: 1,
                    }, transition: {
                        type: "spring",
                        stiffness: 100,
                        damping: 20,
                        delay,
                    }, className: cn("transition-colors duration-200 cursor-pointer", isFocused && "stroke-2"), style: {
                        originY: 1,
                        transformOrigin: "bottom",
                        fill: shouldReduceOpacity
                            ? "var(--color-background-tertiary)"
                            : fillColor,
                        opacity: shouldReduceOpacity ? 0.9 : 1,
                        stroke: isFocused ? "var(--color-primary)" : "none",
                    }, onMouseEnter: (e) => {
                        setHoveredCategory(categoryIndex);
                        // Create tooltip content with all series
                        const series = dataKeys.map((dataKey, idx) => {
                            var _a, _b;
                            const rawValue = item[dataKey];
                            const value = typeof rawValue === "number" && isFinite(rawValue)
                                ? rawValue
                                : 0;
                            return {
                                key: dataKey,
                                label: ((_a = config[dataKey]) === null || _a === void 0 ? void 0 : _a.label) || dataKey,
                                value,
                                color: ((_b = config[dataKey]) === null || _b === void 0 ? void 0 : _b.color) || getSeriesFillColor(idx),
                            };
                        });
                        // Calculate total
                        const total = series.reduce((sum, s) => sum + s.value, 0);
                        const content = {
                            category: item.name || `Category ${categoryIndex + 1}`,
                            series,
                            total,
                        };
                        const svgCoordinates = {
                            x: x + barWidth / 2,
                            y: barY,
                            dimensions,
                        };
                        handleMouseEnter(e, content, svgCoordinates);
                    }, onMouseMove: (e) => {
                        if (hoveredCategory === categoryIndex) {
                            const svgCoordinates = {
                                x: x + barWidth / 2,
                                y: barY,
                                dimensions,
                            };
                            handleMouseMove(e, svgCoordinates);
                        }
                    }, onMouseLeave: () => {
                        setHoveredCategory(null);
                        handleMouseLeave();
                    } }, key));
            }) }, categoryIndex));
    };
    return (jsx(ChartErrorBoundary, { className: className, showErrorDetails: process.env.NODE_ENV === "development", children: jsxs("div", { ref: containerRef, className: cn("chart-container w-full h-full", className), ...chartAccessibilityProps, onMouseEnter: handleMouseInteraction, onMouseMove: handleMouseInteraction, ...props, children: [descriptionProps && jsx("div", { ...descriptionProps }), showValidationWarnings && hasWarnings && (jsxs("div", { className: "absolute top-2 left-2 right-2 z-10 p-2 bg-[var(--color-warning-50)] border border-[var(--color-warning-200)] rounded text-sm text-[var(--color-warning)] shadow-sm", children: [jsx("strong", { children: "Chart Warnings:" }), jsx("ul", { className: "mt-1", children: validation.warnings.map((warning, index) => (jsxs("li", { children: ["\u2022 ", warning.message] }, index))) })] })), jsxs("svg", { width: "100%", height: "100%", viewBox: `0 0 ${dimensions.width} ${dimensions.height}`, children: [jsx(HorizontalGrid, { show: showGrid, x: margin.left, y: margin.top, width: innerWidth, height: innerHeight, lineCount: 5 }), jsx(YAxis, { show: showYAxis, min: minValue, max: maxValue, x: margin.left, y: margin.top, height: innerHeight, showGrid: false, gridWidth: innerWidth, tickFormatter: (value) => {
                                if (stackOffset === "expand")
                                    return `${value}%`;
                                if (Math.abs(value) >= 1000)
                                    return `${(value / 1000).toFixed(0)}k`;
                                return value.toString();
                            } }), jsx("g", { className: "chart-bars", children: sanitizedData.map((item, index) => {
                                const x = margin.left + index * (barWidth + categoryGap);
                                return renderStackedBar(item, index, x);
                            }) }), jsx(XAxis, { show: showXAxis, data: sanitizedData, x: margin.left, y: margin.top + innerHeight, width: innerWidth, categoryWidth: barWidth, categoryGap: categoryGap })] }), jsx(ChartTooltip, { tooltipRef: tooltipRef, content: tooltipData === null || tooltipData === void 0 ? void 0 : tooltipData.content, active: !!tooltipData, position: tooltipData
                        ? { x: tooltipData.x, y: tooltipData.y }
                        : { x: 0, y: 0 } }), children] }) }));
};

export { StackedBarChart };
