import { jsx, jsxs } from 'react/jsx-runtime';
import { createContext, useRef, useState, useEffect, useMemo, useCallback, useContext } from 'react';
import { cn } from '../../../../utils/cn.js';
import { useTooltipPosition } from '../../hooks/useTooltipPosition.js';
import { useChartAccessibility } from '../../hooks/useChartAccessibility.js';
import { ChartErrorBoundary } from '../ChartErrorBoundary/ChartErrorBoundary.js';
import { XAxis } from '../ChartAxis/XAxis.js';
import { YAxis } from '../ChartAxis/YAxis.js';
import { HorizontalGrid } from '../ChartGrid/HorizontalGrid.js';
import { ChartTooltip } from '../ChartTooltip/ChartTooltip.js';

const ChartContext = createContext(null);
/**
 * Hook to access chart context from renderers
 */
const useChartContext = () => {
    const context = useContext(ChartContext);
    if (!context) {
        throw new Error('useChartContext must be used within a ChartContainer');
    }
    return context;
};
/**
 * Default Y-axis tick formatter
 */
const defaultYAxisTickFormatter = (value) => {
    if (Math.abs(value) >= 1000)
        return `${(value / 1000).toFixed(0)}k`;
    return value.toString();
};
/**
 * ChartContainer Component
 *
 * Manages SVG container, axes, grid, tooltip, dimensions, and provides
 * context to child rendering components (BarRenderer, LineRenderer, etc.)
 */
const ChartContainer = ({ children, data, config, scales, dimensions: propDimensions, margins: propMargins, showGrid = true, showXAxis = true, showYAxis = true, gridLineCount = 5, yAxisTickFormatter = defaultYAxisTickFormatter, categoryWidth, categoryGap = 8, className, title, description, enableKeyboardNavigation = true, chartType = 'bar', ...props }) => {
    var _a;
    const containerRef = useRef(null);
    const [dimensions, setDimensions] = useState(propDimensions || { width: 600, height: 400 });
    const [hoveredCategory, setHoveredCategory] = useState(null);
    const [hoveredPoint, setHoveredPoint] = useState(null);
    // Detect if device is mobile/touch
    const isMobile = typeof window !== "undefined" &&
        ("ontouchstart" in window || navigator.maxTouchPoints > 0);
    // Use the tooltip positioning hook
    const { tooltipData, tooltipRef, handleMouseEnter, handleMouseMove, handleMouseLeave, } = useTooltipPosition({
        containerRef,
        isMobile,
    });
    // Use accessibility hook
    const { chartAccessibilityProps, descriptionProps, focusedElementIndex, isKeyboardMode, handleMouseInteraction, } = useChartAccessibility({
        chartType,
        data,
        config,
        title,
        description,
        enableKeyboardNavigation,
    });
    // Measure container dimensions
    useEffect(() => {
        if (propDimensions) {
            setDimensions(propDimensions);
            return;
        }
        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();
        };
    }, [propDimensions]);
    // Calculate margins (can be overridden by prop)
    const margin = useMemo(() => propMargins || {
        top: 15,
        right: showYAxis ? 20 : 0,
        bottom: showXAxis ? 20 : 0,
        left: showYAxis ? 60 : 0,
    }, [propMargins, showYAxis, showXAxis]);
    // 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);
    const dataLength = (_a = data === null || data === void 0 ? void 0 : data.length) !== null && _a !== void 0 ? _a : 0;
    // Derive category width and point positions using the measured width
    const autoCategoryWidth = useMemo(() => {
        if (dataLength === 0)
            return 0;
        if (chartType === "line") {
            if (dataLength === 1) {
                return innerWidth;
            }
            return innerWidth / Math.max(1, dataLength - 1);
        }
        const totalCategoryGap = Math.max(0, (dataLength - 1) * categoryGap);
        const availableWidth = Math.max(0, innerWidth - totalCategoryGap);
        return availableWidth / dataLength;
    }, [chartType, dataLength, innerWidth, categoryGap]);
    const resolvedCategoryWidth = typeof categoryWidth === "number"
        ? categoryWidth
        : autoCategoryWidth;
    const adjustedPointPosition = useCallback((index) => {
        if (dataLength === 0)
            return 0;
        if (chartType === "line") {
            if (dataLength === 1) {
                return innerWidth / 2;
            }
            return (index / Math.max(1, dataLength - 1)) * innerWidth;
        }
        return index * (resolvedCategoryWidth + categoryGap);
    }, [chartType, dataLength, innerWidth, resolvedCategoryWidth, categoryGap]);
    const adjustedScales = useMemo(() => {
        const totalCategoryGap = Math.max(0, (dataLength - 1) * categoryGap);
        const computedTotalWidth = chartType === "line"
            ? innerWidth
            : resolvedCategoryWidth * dataLength + totalCategoryGap;
        return {
            ...scales,
            x: {
                ...scales.x,
                categoryWidth: resolvedCategoryWidth,
                totalWidth: computedTotalWidth,
                pointPosition: adjustedPointPosition,
            },
        };
    }, [
        scales,
        chartType,
        innerWidth,
        dataLength,
        resolvedCategoryWidth,
        categoryGap,
        adjustedPointPosition,
    ]);
    // Create context value
    const contextValue = useMemo(() => ({
        data,
        config,
        scales: adjustedScales,
        dimensions,
        margin,
        innerWidth,
        innerHeight,
        hoveredCategory,
        setHoveredCategory,
        hoveredPoint,
        setHoveredPoint,
        handleMouseEnter,
        handleMouseMove,
        handleMouseLeave,
        focusedElementIndex,
        isKeyboardMode,
    }), [
        data,
        config,
        adjustedScales,
        dimensions,
        margin,
        innerWidth,
        innerHeight,
        hoveredCategory,
        hoveredPoint,
        handleMouseEnter,
        handleMouseMove,
        handleMouseLeave,
        focusedElementIndex,
        isKeyboardMode,
    ]);
    return (jsx(ChartErrorBoundary, { className: className, showErrorDetails: process.env.NODE_ENV === "development", children: jsx(ChartContext.Provider, { value: contextValue, 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 }), 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: gridLineCount }), jsx(YAxis, { show: showYAxis, min: adjustedScales.y.min, max: adjustedScales.y.max, x: margin.left, y: margin.top, height: innerHeight, showGrid: false, gridWidth: innerWidth, tickFormatter: yAxisTickFormatter }), adjustedScales.y.min < 0 && adjustedScales.y.max > 0 && (jsx("line", { x1: margin.left, y1: margin.top + innerHeight - ((0 - adjustedScales.y.min) / (adjustedScales.y.max - adjustedScales.y.min)) * innerHeight, x2: margin.left + innerWidth, y2: margin.top + innerHeight - ((0 - adjustedScales.y.min) / (adjustedScales.y.max - adjustedScales.y.min)) * innerHeight, className: "stroke-[var(--color-text-secondary)]", strokeWidth: 1, opacity: 0.6 })), children, jsx(XAxis, { show: showXAxis, data: data, x: margin.left, y: margin.top + innerHeight, width: innerWidth, categoryWidth: resolvedCategoryWidth, 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 } })] }) }) }));
};

export { ChartContainer, useChartContext };
