import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
import { useCallback, useMemo } from 'react';
import { cn } from '../../../../utils/cn.js';
import { ChartMarker } from '../ChartMarker/ChartMarker.js';
import { ChartCrosshair } from '../ChartCrosshair/ChartCrosshair.js';
import { generateCurvePath } from '../../utils/path-utils.js';

/**
 * Get series color class
 */
const getSeriesColorClass = (index) => {
    const colors = [
        "stroke-[var(--color-primary)]",
        "stroke-[var(--color-warning)]",
        "stroke-[var(--color-success)]",
        "stroke-[var(--color-danger)]",
    ];
    return colors[index % colors.length];
};
/**
 * Get color value for SVG elements and tooltips
 */
const getSeriesFillColor = (index) => {
    const colorVars = [
        "var(--color-primary)",
        "var(--color-warning)",
        "var(--color-success)",
        "var(--color-danger)",
    ];
    return colorVars[index % colorVars.length];
};
/**
 * LineRenderer Component
 *
 * Pure line rendering component that can be used standalone or within ChartContainer.
 * Handles line paths, data points, and crosshair rendering.
 */
const LineRenderer = ({ data, config, scales, dimensions, margin, strokeWidth = 2, curved = true, curveType = "monotone", showDots = true, radius = 4, hoveredPoint: externalHoveredPoint, onHoverPoint, onMouseEnter, onMouseMove, onMouseLeave, focusedElementIndex = -1, isKeyboardMode = false, className, }) => {
    // Get all data keys from config
    const dataKeys = Object.keys(config || {});
    // Calculate inner dimensions
    const innerWidth = Math.max(0, dimensions.width - margin.left - margin.right);
    const innerHeight = Math.max(0, dimensions.height - margin.top - margin.bottom);
    // Get min/max from scales
    const { min: minValue, max: maxValue } = scales.y;
    // Calculate point position
    const getPointPosition = useCallback((dataIndex, value) => {
        const categoryX = scales.x.pointPosition(dataIndex);
        const categoryWidth = scales.x.categoryWidth || 0;
        const x = margin.left + categoryX + categoryWidth / 2;
        const y = margin.top +
            innerHeight -
            ((value - minValue) / (maxValue - minValue)) * innerHeight;
        return { x, y };
    }, [scales.x, margin.left, margin.top, innerHeight, minValue, maxValue]);
    // Generate SVG path for line with null value handling
    const generatePath = useCallback((key) => {
        const segments = [];
        let currentSegment = [];
        data.forEach((item, index) => {
            const rawValue = item[key];
            const isNull = rawValue === null || rawValue === undefined;
            if (isNull) {
                // End current segment and start a new one (creates gap)
                if (currentSegment.length > 0) {
                    segments.push(currentSegment);
                    currentSegment = [];
                }
            }
            else {
                const value = typeof rawValue === "number" ? rawValue : 0;
                const { x, y } = getPointPosition(index, value);
                currentSegment.push({ x, y });
            }
        });
        // Add the last segment if it has points
        if (currentSegment.length > 0) {
            segments.push(currentSegment);
        }
        // Generate path for each segment
        return segments
            .map((segment) => generateCurvePath(segment, curved ? curveType : "linear"))
            .join(" ");
    }, [data, getPointPosition, curved, curveType]);
    // Render lines
    const lines = useMemo(() => {
        return dataKeys.map((key, keyIndex) => {
            var _a;
            const targetPath = generatePath(key);
            const customColor = (_a = config === null || config === void 0 ? void 0 : config[key]) === null || _a === void 0 ? void 0 : _a.color;
            const fallbackClass = getSeriesColorClass(keyIndex);
            const appliedColorClass = customColor ? undefined : fallbackClass;
            return (jsxs("g", { children: [jsx("path", { d: targetPath, fill: "none", strokeWidth: strokeWidth, strokeLinecap: "round", className: cn("transition-all duration-200", appliedColorClass), stroke: customColor, filter: "url(#line-shadow)" }), 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 { x, y } = getPointPosition(dataIndex, value);
                            (externalHoveredPoint === null || externalHoveredPoint === void 0 ? void 0 : externalHoveredPoint.index) === dataIndex &&
                                externalHoveredPoint.key === key;
                            const isFocused = isKeyboardMode && focusedElementIndex === dataIndex;
                            return (jsx("g", { children: jsx(ChartMarker, { cx: x, cy: y, radius: isFocused ? radius + 2 : radius, colorClass: cn(appliedColorClass, isFocused &&
                                        "stroke-[var(--color-primary-600)] stroke-2"), strokeColor: customColor }) }, `${key}-${dataIndex}`));
                        })] }, key));
        });
    }, [
        dataKeys,
        generatePath,
        strokeWidth,
        showDots,
        data,
        getPointPosition,
        externalHoveredPoint,
        focusedElementIndex,
        isKeyboardMode,
        radius,
        config,
    ]);
    // Hover-only markers (when showDots is false)
    const hoverMarkers = useMemo(() => {
        if (showDots || !externalHoveredPoint)
            return null;
        return (jsx("g", { className: "chart-hover-markers", children: dataKeys.map((key, keyIndex) => {
                var _a;
                const item = data[externalHoveredPoint.index];
                const rawValue = item[key];
                const isNull = rawValue === null || rawValue === undefined;
                const value = isNull
                    ? 0
                    : typeof rawValue === "number"
                        ? rawValue
                        : 0;
                if (isNull)
                    return null;
                const { x, y } = getPointPosition(externalHoveredPoint.index, value);
                const customColor = (_a = config === null || config === void 0 ? void 0 : config[key]) === null || _a === void 0 ? void 0 : _a.color;
                const colorClass = customColor ? undefined : getSeriesColorClass(keyIndex);
                return (jsx(ChartMarker, { cx: x, cy: y, radius: radius, colorClass: colorClass, strokeColor: customColor }, `hover-${key}-${externalHoveredPoint.index}`));
            }) }));
    }, [
        showDots,
        externalHoveredPoint,
        dataKeys,
        data,
        getPointPosition,
        radius,
        config,
    ]);
    // Invisible hover areas for multi-series tooltips
    const hoverAreas = useMemo(() => {
        return data.map((item, dataIndex) => {
            const categoryX = scales.x.pointPosition(dataIndex);
            const categoryWidth = scales.x.categoryWidth || 0;
            const pointX = margin.left + categoryX + categoryWidth / 2;
            // Create hover area around each point
            const hoverWidth = categoryWidth;
            const hoverX = margin.left + categoryX;
            return (jsx("rect", { x: hoverX, y: margin.top, width: hoverWidth, height: innerHeight, fill: "transparent", className: "cursor-pointer", onMouseEnter: (e) => {
                    if (onHoverPoint) {
                        onHoverPoint({ index: dataIndex, key: dataKeys[0] });
                    }
                    if (onMouseEnter) {
                        // 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,
                        };
                        const svgCoordinates = {
                            x: pointX,
                            y: margin.top + innerHeight / 2,
                            dimensions,
                        };
                        onMouseEnter(e, content, svgCoordinates);
                    }
                }, onMouseMove: (e) => {
                    if (onMouseMove &&
                        (externalHoveredPoint === null || externalHoveredPoint === void 0 ? void 0 : externalHoveredPoint.index) === dataIndex) {
                        const svgCoordinates = {
                            x: pointX,
                            y: margin.top + innerHeight / 2,
                            dimensions,
                        };
                        onMouseMove(e, svgCoordinates);
                    }
                }, onMouseLeave: () => {
                    if (onMouseLeave) {
                        onMouseLeave();
                    }
                } }, `hover-${dataIndex}`));
        });
    }, [
        data,
        scales.x,
        margin,
        innerHeight,
        dataKeys,
        config,
        dimensions,
        externalHoveredPoint,
        onHoverPoint,
        onMouseEnter,
        onMouseMove,
        onMouseLeave,
    ]);
    return (jsxs(Fragment, { children: [jsxs("defs", { children: [jsx("filter", { id: "line-shadow", x: "-20%", y: "-20%", width: "140%", height: "140%", children: jsx("feDropShadow", { dx: "8", dy: "8", stdDeviation: "8", floodOpacity: "0.15", floodColor: "#000000" }) }), 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(ChartCrosshair, { show: externalHoveredPoint !== null, x: externalHoveredPoint
                    ? margin.left + scales.x.pointPosition(externalHoveredPoint.index) + (scales.x.categoryWidth || 0) / 2
                    : 0, y: externalHoveredPoint && dataKeys.length === 1
                    ? (() => {
                        const item = data[externalHoveredPoint.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("g", { className: cn("chart-lines", className), children: lines }), hoverMarkers, jsx("g", { className: "chart-hover-areas", children: hoverAreas })] }));
};

export { LineRenderer };
