import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import * as d3 from "d3";
import React, { useRef, useEffect } from "react";
import { Svg, Tooltip, Wrapper } from "./d3-linechart.styled";
import { drawFocus, getClosest, showFocus, hideFocus, drawLine, drawXAxis, drawGradient, getExtents, isDefined, } from "../utils/d3";
const init = {
    padding: { top: 20, right: 20, bottom: 20, left: 20 },
    showGrid: { horizontal: false, vertical: false },
    showAxis: { horizontal: false, vertical: false },
    formatterX: (d) => d[0].toString(),
    pointToHuman: ([x, y]) => [x.toString(), y.toString()],
    lineWidth: 2,
    showTooltip: true,
};
const D3LineChart = ({ height, width, charts, isDebugging, padding = init.padding, showAxis = init.showAxis, showGrid = init.showGrid, showTooltip = init.showTooltip, formatterX = init.formatterX, pointToHuman = init.pointToHuman, lineWidth = init.lineWidth, ...rest }) => {
    const svgRef = useRef(null);
    const tooltipRef = useRef(null);
    const nonce = useRef(0);
    useEffect(() => {
        if (!svgRef.current ||
            !padding ||
            !showGrid ||
            !showAxis ||
            !lineWidth ||
            !formatterX ||
            !pointToHuman)
            return;
        if (!charts || charts.length === 0)
            return;
        const svg = d3.select(svgRef.current);
        svg.selectAll("*").remove();
        const { minY, maxY, minX, maxX } = getExtents(charts);
        if (!isDefined(minY) ||
            !isDefined(maxY) ||
            !isDefined(minX) ||
            !isDefined(maxX))
            return;
        nonce.current = nonce.current + 1;
        console.info("Linechart:::draw with nonce", nonce.current);
        isDebugging && console.debug("charts:::", charts);
        isDebugging &&
            console.debug("minY, maxY, minX, maxX:::", minY, maxY, minX, maxX);
        const xScale = d3
            .scaleLinear()
            .domain([minX, maxX])
            .range([padding.left, width - padding.right]);
        const yScale = d3
            .scaleLinear()
            .domain([rest.minY ?? minY, rest.maxY ?? maxY])
            .range([height - padding.bottom, padding.top]);
        showAxis.horizontal &&
            drawXAxis({
                svg,
                xScale,
                yScale,
                height,
                showGrid: showGrid,
                padding,
            });
        const focuses = {};
        charts.forEach((chartPayload) => {
            chartPayload.showGradient &&
                drawGradient({
                    svg,
                    chartPayload,
                    xScale,
                    yScale,
                    minY: rest.minY ?? minY,
                });
            if (chartPayload.showFocus) {
                focuses[chartPayload.color] = drawFocus({
                    svg,
                    color: chartPayload.color,
                });
            }
            drawLine({
                nonce,
                svg,
                chartPayload,
                xScale,
                yScale,
                strokeWidth: lineWidth,
                formatterX,
            });
        });
        const tooltip = d3.select(tooltipRef.current);
        const svgBox = svgRef.current.getBoundingClientRect();
        if (!tooltip || !svgBox)
            return;
        const tooltipsMem = {};
        charts.forEach((chart) => {
            const { id, title, color } = chart;
            chart.serie.forEach((point) => {
                const xFormatted = formatterX(point);
                const newEl = { id, title, color, y: point[1] };
                if (!tooltipsMem[xFormatted]) {
                    tooltipsMem[xFormatted] = [newEl];
                }
                else {
                    tooltipsMem[xFormatted].push(newEl);
                }
            });
        });
        const xOnlySerie = Object.keys(tooltipsMem).map((el) => [
            Number(el),
            0,
        ]);
        svg
            .on("mouseleave", () => {
            tooltip.transition().duration(500).style("opacity", 0);
            Object.values(focuses).forEach((focus) => hideFocus(focus));
            rest.onMousemove && rest.onMousemove(undefined);
        })
            .on("mousemove", (event) => {
            const pointer = d3.pointer(event, svg);
            const x = pointer[0] - svgBox.left;
            const y = pointer[1] - svgBox.top;
            const [xVal] = getClosest({ x, xScale, serie: xOnlySerie });
            if (!xVal || !tooltipsMem[xVal])
                return;
            if (showTooltip) {
                const info = tooltipsMem[xVal].reduce((acc, { id, title, color, y }) => `${acc}<p class="tooltip-label ${id}" style="color:${color}"><span>${title}</span>&nbsp;&nbsp;<span>${pointToHuman([0, y])[1]}</span></p>`, "");
                tooltip
                    .html(`<p class="tooltip-label x">${pointToHuman([xVal, 0])[0]}</p>${info}`)
                    // TODO: refactor magic numbers
                    .style("opacity", 0.9)
                    .style("left", x - 20 + "px")
                    .style("top", y - 100 + "px");
            }
            Object.values(focuses).forEach((focus) => hideFocus(focus));
            tooltipsMem[xVal].forEach(({ color, y }) => {
                if (color in focuses) {
                    showFocus({
                        focus: focuses[color],
                        xScale,
                        yScale,
                        closest: [xVal, y],
                    });
                }
            });
            rest.onMousemove && rest.onMousemove(xVal);
        });
    }, [
        svgRef,
        formatterX,
        charts,
        showGrid,
        width,
        height,
        padding,
        lineWidth,
        pointToHuman,
        rest.minY,
        rest.maxY,
        showAxis,
        rest,
        showTooltip,
    ]);
    return (_jsxs(Wrapper, { className: "ui-d3linechart__wrapper", children: [_jsx(Svg, { className: "ui-d3linechart__svg", style: { height, width }, ref: svgRef }), _jsx(Tooltip, { className: "ui-d3linechart__tooltip", ref: tooltipRef })] }));
};
const areEqual = (prevProps, nextProps) => {
    if (nextProps.width !== prevProps.width) {
        return false;
    }
    let result = true;
    const prev = prevProps.charts.flatMap((el) => el.serie);
    const next = nextProps.charts.flatMap((el) => el.serie);
    if (prev.length !== next.length)
        return false;
    const size = prev.length;
    for (let i = 0; i < size; i++) {
        if (prev[i][1] !== next[i][1]) {
            result = false;
        }
    }
    return result;
};
export default React.memo(D3LineChart, areEqual);
//# sourceMappingURL=d3-linechart.js.map