import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React, { useRef, useState, useEffect } from "react";
import { Svg, Tooltip, Wrapper, HighlightedPoint } from "./styled";
import * as d3 from "d3";
import { drawXAxis, drawYAxis, drawGradient, drawLine, drawFocus, getClosest, getTooltipClass, groupTooltipPoints, hideTooltip, showFocus, showTooltips, getExtents, hideFocus, formatterDateDay, formatterDateMonth, getClosestAddon, highlightPoint, } from "./hooks";
const init = {
    margin: { top: 20, right: 20, bottom: 20, left: 20 },
    padding: { top: 20, right: 20, bottom: 20, left: 20 },
    showGrid: { horizontal: false, vertical: false },
    mapFn: (el) => [el[0], el[1]],
    formatterX: (d) => d.toString(),
    formatterYRight: (d) => d.toString(),
    formatterYLeft: (d) => d.toString(),
    scaleFonts: { fontSize: 10, fontFamily: "Regular" },
    lineWidth: 2,
};
const D3LineChart = ({ height, width, payload, margin = init.margin, padding = init.padding, showGrid = init.showGrid, mapFn = init.mapFn, formatterX = init.formatterX, formatterYRight = init.formatterYRight, formatterYLeft = init.formatterYLeft, lineWidth = init.lineWidth, scaleFonts = init.scaleFonts, showGradient = true, tooltipFormatter, showTooltip = true, additionalMapFn, highlightedPoint, ...props }) => {
    const svgRef = useRef(null);
    const [series, setSeries] = useState([]);
    useEffect(() => {
        const seriesNext = [];
        if (payload && Array.isArray(payload)) {
            payload.forEach(({ title, color, data, minY, maxY }, i) => {
                if (Array.isArray(data) && data.length > 0) {
                    const tooltip = d3.select("." + getTooltipClass(props.title, title));
                    const serie = data.map(mapFn);
                    const additionalDataSerie = additionalMapFn
                        ? data.map(additionalMapFn)
                        : undefined;
                    const extents = d3.extent(serie, (d) => d[1]);
                    let min = extents[0];
                    let max = extents[1];
                    if (minY || minY === 0) {
                        if (typeof minY === "number") {
                            min = minY;
                        }
                    }
                    if (maxY) {
                        if (typeof maxY === "number") {
                            max = maxY;
                        }
                    }
                    const yScale = d3
                        .scaleLinear()
                        // @ts-ignore
                        .domain([min, max])
                        .range([height - margin.bottom, margin.top]);
                    seriesNext.push({
                        title,
                        color,
                        serie,
                        yScale,
                        tooltip: showTooltip ? tooltip : undefined,
                        additionalDataSerie,
                    });
                }
            });
        }
        setSeries(seriesNext);
    }, [payload, props.title, mapFn]);
    const [focuses, setFocuses] = useState();
    useEffect(() => {
        console.info("draw chart =>", props.title);
        const { minX, maxX } = getExtents(series.map((el) => el.serie));
        if (!minX || !maxX || !svgRef.current)
            return;
        const svg = d3.select(svgRef.current);
        const svgNode = svg.node();
        if (!svgNode)
            return;
        const svgBox = svgNode.getBoundingClientRect();
        const focuses = [];
        // TODO: Range => rangeRound ??
        const xScale = d3
            .scaleLinear()
            .domain([minX, maxX])
            .range([margin.left, width - margin.right]);
        drawXAxis({
            svg,
            xScale,
            height,
            margin: margin,
            showGrid: showGrid,
            ticksX: props.ticksX ?? Math.floor(width / 100),
            formatterX: formatterX,
            scaleFonts: scaleFonts,
        });
        drawYAxis({
            svg,
            yScaleLeft: series[0].yScale,
            yScaleRight: series.length === 2 ? series[1].yScale : null,
            width,
            margin: margin,
            showGrid: showGrid,
            ticksY: props.ticksY ?? Math.floor(width / 100),
            formatterYLeft: formatterYLeft,
            formatterYRight: formatterYRight,
            scaleFonts: scaleFonts,
        });
        showGradient &&
            series.forEach(({ color, serie, yScale }) => {
                drawGradient({
                    svg,
                    serie,
                    xScale,
                    yScale,
                    color,
                });
            });
        series.forEach(({ color, serie, yScale }) => {
            drawLine({
                svg,
                color,
                serie,
                xScale,
                yScale,
                lineWidth: lineWidth,
            });
        });
        series.forEach(({ color }) => {
            focuses.push(drawFocus({
                svg,
                color,
            }));
        });
        setFocuses(focuses);
    }, [series, svgRef, formatterX]);
    useEffect(() => {
        const { minX, maxX, minY, maxY } = getExtents(series.map((el) => el.serie));
        if (!minX || !maxX || !minY || !maxY)
            return;
        const xScale = d3
            .scaleLinear()
            .domain([minX, maxX])
            .range([margin.left, width - margin.right]);
        const yScale = d3
            .scaleLinear()
            // @ts-ignore
            .domain([minY, maxY])
            .range([height - margin.bottom, margin.top]);
        highlightedPoint &&
            highlightPoint(xScale(highlightedPoint.point[0]), yScale(highlightedPoint.point[1]));
    }, [height, highlightedPoint, margin, series, width]);
    useEffect(() => {
        if (focuses) {
            const { minX, maxX } = getExtents(series.map((el) => el.serie));
            const svg = d3.select(svgRef.current);
            if (!minX || !maxX || !svgRef.current)
                return;
            const svgNode = svg.node();
            if (!svgNode)
                return;
            const svgBox = svgNode.getBoundingClientRect();
            const xScale = d3
                .scaleLinear()
                .domain([minX, maxX])
                .range([margin.left, width - margin.right]);
            svg.on("mousemove", (event) => {
                const { x } = event;
                const tooltips = [];
                const xAdjusted = x - svgBox.left;
                series.forEach(({ serie, color, tooltip, yScale, additionalDataSerie }, i) => {
                    if (tooltip &&
                        // @ts-ignore
                        tooltip.node &&
                        xAdjusted > margin.left &&
                        xAdjusted < width - margin.right) {
                        const focus = focuses[i];
                        const closest = getClosest({ x: xAdjusted, xScale, serie });
                        const closestAddon = additionalDataSerie
                            ? getClosestAddon({
                                x: xAdjusted,
                                xScale,
                                serie,
                                additionalDataSerie,
                            })
                            : undefined;
                        showFocus({ focus, xScale, yScale, closest });
                        tooltips.push({
                            tooltip,
                            yScale,
                            color,
                            point: closest,
                            additionalData: closestAddon,
                        });
                    }
                });
                const tooltipsGrouped = groupTooltipPoints(tooltips);
                tooltipsGrouped.forEach((group) => {
                    showTooltips({
                        x: xAdjusted,
                        tooltips: group,
                        xScale,
                        width,
                        tooltipFormatter,
                    });
                });
            });
            svg.on("mouseout", () => {
                series.forEach(({ tooltip }, i) => {
                    const focus = focuses[i];
                    hideFocus(focus);
                    if (tooltip)
                        hideTooltip(tooltip);
                });
            });
        }
    }, [svgRef, series, tooltipFormatter, focuses]);
    return (_jsxs(Wrapper, { className: "ui-d3linechart__wrapper", children: [_jsx(Svg, { className: "ui-d3linechart__svg", style: { height, width }, ref: svgRef }), payload.map((el) => (_jsx(Tooltip, { color: el.color, className: `ui-d3linechart__tooltip ${getTooltipClass(props.title, el.title)}` }, el.title))), highlightedPoint && (_jsx(HighlightedPoint, { bg: payload[0]?.color, className: "ui-d3linechart__highlighted-point", children: highlightedPoint.label }))] }));
};
const areEqual = (prevProps, nextProps) => {
    let result = true;
    const prev = prevProps.payload.map((el) => el.data);
    const next = nextProps.payload.map((el) => el.data);
    if (prev.length !== next.length)
        return false;
    const size = prev.length;
    for (let i = 0; i < size; i++) {
        if (prev[i].length !== next[i].length) {
            result = false;
        }
        if (prev[i][0] !== next[i][0]) {
            result = false;
        }
        if (size > 0 && prev[i][size - 1] !== next[i][size - 1]) {
            result = false;
        }
    }
    return result;
};
const Memo = React.memo(D3LineChart, areEqual);
export default Object.assign(D3LineChart, {
    Memo,
    formatterDateDay,
    formatterDateMonth,
});
//# sourceMappingURL=index.js.map