import { jsx, jsxs } from 'react/jsx-runtime';
import { useRef, useState, useId, useEffect, useMemo, useCallback } from 'react';
import { motion } from 'motion/react';
import { cn } from '../../../utils/cn.js';
import { useTooltipPosition } from '../hooks/useTooltipPosition.js';
import { useChartAccessibility } from '../hooks/useChartAccessibility.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 { ChartMarker } from '../shared/ChartMarker/ChartMarker.js';
import { ChartCrosshair } from '../shared/ChartCrosshair/ChartCrosshair.js';
import { generateNiceTicks } from '../utils/chart-validation.js';
import { generateCurvePath } from '../utils/path-utils.js';
import { AREA_CHART_DEFAULTS } from './AreaChart.types.js';
import { areaChartTheme, getSeriesFillColor, getSeriesColorClass } from './AreaChart.theme.js';

const AreaChart = ({ data, config, 
// Standardized display props with defaults
showGrid = AREA_CHART_DEFAULTS.showGrid, showXAxis = AREA_CHART_DEFAULTS.showXAxis, showYAxis = AREA_CHART_DEFAULTS.showYAxis, minValue: propMinValue, maxValue: propMaxValue, variant = AREA_CHART_DEFAULTS.variant, theme, 
// Standardized visual props with defaults (renamed from area-specific names)
dotRadius, radius, // @deprecated Use dotRadius instead
strokeWidth = AREA_CHART_DEFAULTS.strokeWidth, curved = AREA_CHART_DEFAULTS.curved, curveType = AREA_CHART_DEFAULTS.curveType, showDots = AREA_CHART_DEFAULTS.showDots, fillOpacity = AREA_CHART_DEFAULTS.fillOpacity, showStroke = AREA_CHART_DEFAULTS.showStroke, stacked = AREA_CHART_DEFAULTS.stacked, 
// Base props
className, title, description, enableKeyboardNavigation = AREA_CHART_DEFAULTS.enableKeyboardNavigation, 
// Additional className overrides for chart elements
svgClassName, areaClassName, lineClassName, gridClassName, axisClassName, children, ...props }) => {
    var _a;
    // Resolve dotRadius with backward compatibility
    const resolvedDotRadius = (_a = dotRadius !== null && dotRadius !== void 0 ? dotRadius : radius) !== null && _a !== void 0 ? _a : AREA_CHART_DEFAULTS.dotRadius;
    // Development warning for deprecated radius prop
    if (process.env.NODE_ENV !== "production" && radius !== undefined) {
        console.warn("[AreaChart]: The `radius` prop is deprecated and will be removed in a future version. " +
            "Use `dotRadius` instead.");
    }
    // Simplified color system - no complex theme hook needed
    const containerRef = useRef(null);
    const [dimensions, setDimensions] = useState({ width: 600, height: 400 });
    const clipId = useId();
    const revealClipId = useId();
    const shadowFilterId = useId();
    const ANIMATION_DURATION = 1.5;
    const [hoveredPoint, setHoveredPoint] = useState(null);
    // Detect if device is mobile/touch
    const isMobile = typeof window !== "undefined" &&
        ("ontouchstart" in window || navigator.maxTouchPoints > 0);
    // Use the new tooltip positioning hook
    const { tooltipData, tooltipRef, handleMouseEnter, handleMouseMove, handleMouseLeave, } = useTooltipPosition({
        containerRef,
        isMobile,
    });
    // Use accessibility hook
    const { chartAccessibilityProps, descriptionProps, handleMouseInteraction } = useChartAccessibility({
        chartType: "area",
        data,
        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();
        };
    }, []);
    // Early return if no data
    if (!data || data.length === 0) {
        return (jsx("div", { className: cn(areaChartTheme.emptyStateStyle, className), role: "img", "aria-label": "Empty area chart", ...props, children: jsx("span", { children: "No data available" }) }));
    }
    // Calculate dimensions
    const margin = useMemo(() => ({
        top: 0,
        right: 0,
        bottom: showXAxis ? 40 : 0,
        left: showYAxis ? 60 : 0,
    }), [showXAxis, showYAxis]);
    const innerWidth = dimensions.width - margin.left - margin.right;
    const innerHeight = dimensions.height - margin.top - margin.bottom;
    // Get all data keys from config
    const dataKeys = useMemo(() => Object.keys(config), [config]);
    // Calculate scales
    const { minValue, maxValue } = useMemo(() => {
        const rawMaxValue = Math.max(...data.map((item) => stacked
            ? dataKeys.reduce((sum, key) => {
                const value = item[key];
                return sum + (typeof value === "number" ? value : 0);
            }, 0)
            : Math.max(...dataKeys.map((key) => {
                const value = item[key];
                return typeof value === "number" ? value : 0;
            }))));
        const rawMinValue = Math.min(...data.map((item) => Math.min(...dataKeys.map((key) => {
            const value = item[key];
            return typeof value === "number" ? value : 0;
        }))));
        // Compute nice axis boundaries using Heckbert's algorithm
        const dataMinWithZero = Math.min(rawMinValue, 0);
        const dataMaxWithZero = Math.max(rawMaxValue, 0);
        const { niceMin, niceMax } = generateNiceTicks(dataMinWithZero, dataMaxWithZero, 5);
        return {
            minValue: propMinValue !== null && propMinValue !== void 0 ? propMinValue : niceMin,
            maxValue: propMaxValue !== null && propMaxValue !== void 0 ? propMaxValue : niceMax,
        };
    }, [data, dataKeys, stacked, propMinValue, propMaxValue]);
    // Calculate point position
    const getPointPosition = useCallback((dataIndex, value) => {
        // Spread points evenly across the full width
        // First point at left edge (margin.left), last point at right edge (margin.left + innerWidth)
        const x = data.length === 1
            ? margin.left + innerWidth / 2 // Center single point
            : margin.left + (dataIndex / (data.length - 1)) * innerWidth;
        const y = margin.top +
            innerHeight -
            ((value - minValue) / (maxValue - minValue)) * innerHeight;
        return { x, y };
    }, [data.length, margin.left, margin.top, innerWidth, innerHeight, minValue, maxValue]);
    // Calculate stacked values for each data point
    const getStackedValues = () => {
        if (!stacked)
            return {};
        const stackedData = {};
        const cumulativeValues = new Array(data.length).fill(0);
        dataKeys.forEach((key) => {
            stackedData[key] = [...cumulativeValues];
            data.forEach((item, index) => {
                const rawValue = item[key];
                const value = typeof rawValue === "number" ? rawValue : 0;
                cumulativeValues[index] += value;
            });
        });
        return stackedData;
    };
    const stackedValues = useMemo(() => getStackedValues(), [data, dataKeys, stacked]);
    // Precompute all paths for each data key
    const allPaths = useMemo(() => {
        const result = {};
        dataKeys.forEach((key) => {
            const segments = [];
            let currentSegment = {
                points: [],
                baselinePoints: [],
            };
            const seriesStackedValues = stackedValues[key];
            data.forEach((item, index) => {
                const rawValue = item[key];
                const isNull = rawValue === null || rawValue === undefined;
                if (isNull) {
                    if (currentSegment.points.length > 0) {
                        segments.push(currentSegment);
                        currentSegment = { points: [], baselinePoints: [] };
                    }
                }
                else {
                    const value = typeof rawValue === "number" ? rawValue : 0;
                    let baselineValue = stacked && seriesStackedValues
                        ? seriesStackedValues[index]
                        : 0;
                    let topValue = stacked && seriesStackedValues
                        ? seriesStackedValues[index] + value
                        : value;
                    const topPoint = getPointPosition(index, topValue);
                    const baselinePoint = getPointPosition(index, baselineValue);
                    currentSegment.points.push(topPoint);
                    currentSegment.baselinePoints.push(baselinePoint);
                }
            });
            if (currentSegment.points.length > 0) {
                segments.push(currentSegment);
            }
            if (segments.length === 0) {
                result[key] = null;
                return;
            }
            const areaPaths = [];
            const linePaths = [];
            segments.forEach((segment) => {
                if (segment.points.length > 0) {
                    const topPath = generateCurvePath(segment.points, curved ? curveType : "linear");
                    const reversedBaselinePoints = [...segment.baselinePoints].reverse();
                    const baselinePath = generateCurvePath(reversedBaselinePoints, curved ? curveType : "linear");
                    const areaPath = `${topPath} L ${segment.baselinePoints[segment.baselinePoints.length - 1].x} ${segment.baselinePoints[segment.baselinePoints.length - 1].y} ${baselinePath.replace("M", "L")} Z`;
                    areaPaths.push(areaPath);
                    linePaths.push(topPath);
                }
            });
            result[key] = {
                areaPath: areaPaths.join(" "),
                linePath: linePaths.join(" "),
            };
        });
        return result;
    }, [data, dataKeys, stacked, stackedValues, curved, curveType, getPointPosition]);
    return (jsxs("div", { ref: containerRef, className: cn(areaChartTheme.containerStyle, className), ...chartAccessibilityProps, onMouseEnter: handleMouseInteraction, onMouseMove: handleMouseInteraction, ...props, children: [descriptionProps && jsx("div", { ...descriptionProps }), jsxs("svg", { width: "100%", height: "100%", viewBox: `0 0 ${dimensions.width} ${dimensions.height}`, className: cn(areaChartTheme.svgStyle, svgClassName), role: "presentation", children: [jsxs("defs", { children: [jsx("filter", { id: shadowFilterId, x: "-20%", y: "-20%", width: "140%", height: "140%", children: jsx("feDropShadow", { dx: "4", dy: "4", stdDeviation: "6", floodOpacity: "0.1", floodColor: "#000000" }) }), jsx("clipPath", { id: clipId, children: jsx("rect", { x: margin.left, y: margin.top, width: innerWidth, height: innerHeight }) }), jsx("clipPath", { id: revealClipId, children: jsx(motion.rect
                                // Explicitly set x/y in initial to prevent 0,0 glitch
                                , { 
                                    // Explicitly set x/y in initial to prevent 0,0 glitch
                                    initial: { width: 0, x: margin.left, y: margin.top }, animate: {
                                        width: innerWidth + margin.right,
                                        x: margin.left,
                                        y: margin.top,
                                    }, height: innerHeight, transition: {
                                        duration: ANIMATION_DURATION,
                                        ease: "easeOut",
                                    } }) }), dataKeys.map((key, keyIndex) => {
                                const fillColor = getSeriesFillColor(keyIndex);
                                return (jsxs("linearGradient", { id: `area-gradient-${key}`, x1: "0%", y1: "0%", x2: "0%", y2: "100%", children: [jsx("stop", { offset: "0%", stopColor: fillColor, stopOpacity: fillOpacity * 0.8 }), jsx("stop", { offset: "100%", stopColor: fillColor, stopOpacity: fillOpacity * 0.05 })] }, `gradient-${key}`));
                            }), jsxs("linearGradient", { id: "vertical-fade", x1: "0%", y1: "0%", x2: "0%", y2: "100%", children: [jsx("stop", { offset: "0%", stopColor: "#6b7280", stopOpacity: "0" }), jsx("stop", { offset: "40%", stopColor: "#6b7280", stopOpacity: "0.3" }), jsx("stop", { offset: "50%", stopColor: "#6b7280", stopOpacity: "0.5" }), jsx("stop", { offset: "60%", stopColor: "#6b7280", stopOpacity: "0.3" }), jsx("stop", { offset: "100%", stopColor: "#6b7280", stopOpacity: "0" })] }), jsxs("linearGradient", { id: "horizontal-fade", x1: "0%", y1: "0%", x2: "100%", y2: "0%", children: [jsx("stop", { offset: "0%", stopColor: "#6b7280", stopOpacity: "0" }), jsx("stop", { offset: "40%", stopColor: "#6b7280", stopOpacity: "0.3" }), jsx("stop", { offset: "50%", stopColor: "#6b7280", stopOpacity: "0.5" }), jsx("stop", { offset: "60%", stopColor: "#6b7280", stopOpacity: "0.3" }), jsx("stop", { offset: "100%", stopColor: "#6b7280", stopOpacity: "0" })] })] }), jsx(HorizontalGrid, { show: showGrid, x: margin.left, y: margin.top, width: innerWidth, height: innerHeight, lineCount: 5, className: gridClassName }), jsx(ChartCrosshair, { show: hoveredPoint !== null, x: hoveredPoint !== null
                            ? data.length === 1
                                ? margin.left + innerWidth / 2
                                : margin.left +
                                    (hoveredPoint.index / (data.length - 1)) * innerWidth
                            : 0, y: hoveredPoint !== null && dataKeys.length === 1
                            ? (() => {
                                const item = data[hoveredPoint.index];
                                const singleKey = dataKeys[0];
                                const singleValue = item[singleKey];
                                const numValue = typeof singleValue === "number" ? singleValue : 0;
                                return (margin.top +
                                    innerHeight -
                                    ((numValue - minValue) / (maxValue - minValue)) *
                                        innerHeight);
                            })()
                            : undefined, margin: margin, innerWidth: innerWidth, innerHeight: innerHeight, showHorizontal: dataKeys.length === 1 }), jsx(YAxis, { show: showYAxis, min: minValue, max: maxValue, x: margin.left, y: margin.top, height: innerHeight, showGrid: false, gridWidth: innerWidth, className: axisClassName, tickFormatter: (value) => {
                            if (Math.abs(value) >= 1000)
                                return `${(value / 1000).toFixed(0)}k`;
                            return value.toString();
                        } }), minValue < 0 && maxValue > 0 && (jsx("line", { x1: margin.left, y1: margin.top + innerHeight - ((0 - minValue) / (maxValue - minValue)) * innerHeight, x2: margin.left + innerWidth, y2: margin.top + innerHeight - ((0 - minValue) / (maxValue - minValue)) * innerHeight, className: "stroke-[var(--color-text-secondary)]", strokeWidth: 1, opacity: 0.6 })), jsx("g", { className: cn(areaChartTheme.areaGroupStyle, areaClassName), clipPath: `url(#${clipId})`, children: dataKeys.map((key, keyIndex) => {
                            const paths = allPaths[key];
                            const colorClass = getSeriesColorClass(keyIndex);
                            if (!paths)
                                return null;
                            return (jsxs("g", { clipPath: `url(#${revealClipId})`, children: [jsx("path", { d: paths.areaPath, fill: `url(#area-gradient-${key})`, className: "transition-colors duration-200", filter: `url(#${shadowFilterId})` }), showStroke && (jsx(motion.path, { d: paths.linePath, 
                                        // Removed pathLength animation in favor of clipPath for perfect sync with area
                                        initial: { opacity: 1 }, animate: { opacity: 1 }, fill: "none", strokeWidth: strokeWidth, strokeLinecap: "round", className: cn("transition-colors duration-200", colorClass
                                            .split(" ")
                                            .find((cls) => cls.startsWith("stroke-")) || "", lineClassName) })), showDots &&
                                        data.map((item, dataIndex) => {
                                            const rawValue = item[key];
                                            const isNull = rawValue === null || rawValue === undefined;
                                            const value = isNull
                                                ? 0
                                                : typeof rawValue === "number"
                                                    ? rawValue
                                                    : 0;
                                            // Don't render dots for null values
                                            if (isNull)
                                                return null;
                                            const topValue = stacked && stackedValues[key]
                                                ? stackedValues[key][dataIndex] + value
                                                : value;
                                            const { x, y } = getPointPosition(dataIndex, topValue);
                                            return (jsx(motion.g, { initial: { opacity: 0, scale: 0 }, animate: { opacity: 1, scale: 1 }, transition: {
                                                    // Sync with the line reveal: calculate when the line reaches this point
                                                    delay: (dataIndex / (data.length - 1)) *
                                                        ANIMATION_DURATION,
                                                    type: "spring",
                                                    stiffness: 260,
                                                    damping: 20,
                                                }, style: {
                                                    originX: "50%",
                                                    originY: "50%",
                                                    transformBox: "fill-box",
                                                }, children: jsx(ChartMarker, { cx: x, cy: y, radius: resolvedDotRadius, colorClass: colorClass }) }, `${key}-${dataIndex}`));
                                        })] }, key));
                        }) }), !showDots && hoveredPoint !== null && (jsx("g", { className: "chart-hover-markers", children: dataKeys.map((key, keyIndex) => {
                            const item = data[hoveredPoint.index];
                            const rawValue = item[key];
                            const isNull = rawValue === null || rawValue === undefined;
                            const value = isNull
                                ? 0
                                : typeof rawValue === "number"
                                    ? rawValue
                                    : 0;
                            // Don't render hover markers for null values
                            if (isNull)
                                return null;
                            const topValue = stacked && stackedValues[key]
                                ? stackedValues[key][hoveredPoint.index] + value
                                : value;
                            const { x, y } = getPointPosition(hoveredPoint.index, topValue);
                            const colorClass = getSeriesColorClass(keyIndex);
                            return (jsx(ChartMarker, { cx: x, cy: y, radius: resolvedDotRadius, colorClass: colorClass }, `hover-${key}-${hoveredPoint.index}`));
                        }) })), jsx("g", { className: "chart-hover-areas", children: data.map((item, dataIndex) => {
                            // Calculate hover area based on new point positioning
                            const pointX = data.length === 1
                                ? margin.left + innerWidth / 2
                                : margin.left + (dataIndex / (data.length - 1)) * innerWidth;
                            // Create hover area around each point
                            const hoverWidth = data.length === 1 ? innerWidth : innerWidth / (data.length - 1);
                            const hoverX = data.length === 1
                                ? margin.left
                                : Math.max(margin.left, pointX - hoverWidth / 2);
                            // Ensure hover area doesn't exceed chart bounds
                            const adjustedWidth = data.length === 1
                                ? innerWidth
                                : Math.min(hoverWidth, margin.left + innerWidth - hoverX);
                            return (jsx("rect", { x: hoverX, y: margin.top, width: adjustedWidth, height: innerHeight, fill: "transparent", className: "cursor-pointer", onMouseEnter: (e) => {
                                    setHoveredPoint({ index: dataIndex, key: dataKeys[0] });
                                    // Create multi-series tooltip data
                                    const seriesData = dataKeys.map((seriesKey, keyIndex) => {
                                        var _a, _b;
                                        const seriesValue = item[seriesKey];
                                        const numValue = typeof seriesValue === "number" ? seriesValue : 0;
                                        return {
                                            key: seriesKey,
                                            label: ((_a = config[seriesKey]) === null || _a === void 0 ? void 0 : _a.label) || seriesKey,
                                            value: numValue,
                                            color: ((_b = config[seriesKey]) === null || _b === void 0 ? void 0 : _b.color) ||
                                                getSeriesFillColor(keyIndex),
                                        };
                                    });
                                    const content = {
                                        category: item.name || `Category ${dataIndex + 1}`,
                                        series: seriesData,
                                    };
                                    // Only pass SVG coordinates on mobile for fixed positioning
                                    // On desktop, let the hook use mouse coordinates for cursor-following
                                    const svgCoordinates = isMobile
                                        ? {
                                            x: pointX,
                                            y: margin.top + innerHeight / 2,
                                            dimensions,
                                        }
                                        : undefined;
                                    handleMouseEnter(e, content, svgCoordinates);
                                }, onMouseMove: (e) => {
                                    if ((hoveredPoint === null || hoveredPoint === void 0 ? void 0 : hoveredPoint.index) === dataIndex) {
                                        // Only pass SVG coordinates on mobile
                                        const svgCoordinates = isMobile
                                            ? {
                                                x: pointX,
                                                y: margin.top + innerHeight / 2,
                                                dimensions,
                                            }
                                            : undefined;
                                        handleMouseMove(e, svgCoordinates);
                                    }
                                }, onMouseLeave: handleMouseLeave }, `hover-${dataIndex}`));
                        }) }), jsx(XAxis, { show: showXAxis, data: data, x: margin.left, y: margin.top + innerHeight, width: innerWidth, categoryWidth: innerWidth / data.length, categoryGap: 0, className: axisClassName, alignWithEdge: true })] }), jsx(ChartTooltip, { active: !!tooltipData, position: tooltipData ? { x: tooltipData.x, y: tooltipData.y } : { x: 0, y: 0 }, tooltipRef: tooltipRef, content: tooltipData === null || tooltipData === void 0 ? void 0 : tooltipData.content, chartType: "area" }), children] }));
};

export { AreaChart };
