import { isNullish } from "remeda";
import { array, clamper, regressionLinear, regressionLogistic, regressionLowess, regressionPolynomial } from "@visactor/vutils";
const generateRegressionLinePipe = (type, regressionFunction, getOptions = getDefaultRegressionOptions)=>(spec, context)=>{
        const result = {
            ...spec
        };
        const { advancedVSeed } = context;
        const { chartType, regressionLine } = advancedVSeed;
        const lineTheme = advancedVSeed.config[chartType]?.regressionLine;
        if (!regressionLine || !regressionLine[type]) return result;
        const lineList = array(regressionLine[type]);
        if (!result.customMark) result.customMark = [];
        lineList.forEach((line, lineIndex)=>{
            const theme = lineTheme.linearRegressionLine ?? {};
            const { color, lineWidth, lineDash, text, textColor, textFontSize, textFontWeight, confidenceIntervalOpacity, confidenceIntervalVisible = theme.confidenceIntervalVisible } = line;
            const childrenMarks = [];
            result.customMark.push({
                type: 'group',
                interactive: false,
                zIndex: 500,
                name: `${type}-${lineIndex}`,
                style: {
                    data: (datum, ctx)=>{
                        const vchart = ctx.vchart;
                        const chart = vchart.getChart();
                        const s = chart.getAllSeries()[0];
                        if (s) {
                            const rect = s.getRegion().getLayoutRect();
                            const segments = [];
                            if (0 === rect.width || 0 === rect.height) return segments;
                            const start = s.getRegion().getLayoutStartPoint();
                            const yClamper = clamper(start.y, start.y + rect.height);
                            const colorAttrOptions = s.getColorAttribute();
                            const groups = s.getSeriesKeys();
                            const data = s.getViewData()?.latestData;
                            const fieldX = s.fieldX?.[0];
                            const fieldY = s.fieldY?.[0];
                            if (!groups.length) groups.push(void 0);
                            groups.forEach((group)=>{
                                const groupData = data.filter((d)=>d[colorAttrOptions?.field] === group);
                                if (!groupData.length) return;
                                const { confidenceInterval, evaluateGrid } = regressionFunction(groupData, (datum)=>datum?.[fieldX], (datum)=>datum?.[fieldY], getOptions?.(line));
                                const N = Math.max(3, Math.floor(groupData.length / 4));
                                const mainColor = color ?? colorAttrOptions?.scale?.scale(group);
                                const lineData = evaluateGrid(N);
                                const linePoints = lineData.map((ld)=>{
                                    const d = {
                                        [fieldX]: ld.x,
                                        [fieldY]: ld.y
                                    };
                                    return {
                                        x: s.dataToPositionX(d) + start.x,
                                        y: yClamper(s.dataToPositionY(d) + start.y)
                                    };
                                });
                                segments.push({
                                    color: mainColor,
                                    linePoints
                                });
                                if (confidenceIntervalVisible) {
                                    const intervalData = confidenceInterval(N);
                                    const areaPoints = intervalData.map((datum)=>{
                                        const d = {
                                            [fieldX]: datum.x,
                                            [fieldY]: datum.lower
                                        };
                                        return {
                                            x: s.dataToPositionX(d) + start.x,
                                            y: yClamper(s.dataToPositionY(d) + start.y),
                                            y1: yClamper(s.dataToPositionY({
                                                [fieldY]: datum.upper
                                            }) + start.y)
                                        };
                                    });
                                    segments[segments.length - 1].areaPoints = areaPoints;
                                }
                            });
                            return segments;
                        }
                        return [];
                    }
                },
                children: childrenMarks
            });
            if (confidenceIntervalVisible) childrenMarks.push({
                type: 'area',
                interactive: false,
                zIndex: 500,
                style: {
                    lineWidth: lineWidth ?? theme.lineWidth,
                    lineDash: lineDash ?? theme.lineDash,
                    fillOpacity: confidenceIntervalOpacity ?? theme.confidenceIntervalOpacity,
                    fill: 'red',
                    segments: (datum, ctx, opt)=>{
                        const parentNode = opt.mark?._product?.parent;
                        if (parentNode?.attribute?.data?.length) return parentNode.attribute.data.map((d)=>({
                                points: d.areaPoints ?? [],
                                fill: d.color
                            }));
                        return [];
                    }
                }
            });
            childrenMarks.push({
                type: 'line',
                interactive: false,
                zIndex: 500,
                style: {
                    lineWidth: lineWidth ?? theme.lineWidth,
                    lineDash: lineDash ?? theme.lineDash,
                    stroke: 'red',
                    segments: (datum, ctx, opt)=>{
                        const parentNode = opt.mark?._product?.parent;
                        if (parentNode?.attribute?.data?.length) return parentNode.attribute.data.map((d)=>({
                                points: d.linePoints,
                                stroke: d.color
                            }));
                        return [];
                    }
                }
            });
            if (!isNullish(text)) childrenMarks.push({
                type: 'text',
                interactive: false,
                zIndex: 500,
                style: {
                    textAlign: 'end',
                    fill: textColor ?? theme.textColor,
                    fontSize: textFontSize ?? theme.textFontSize,
                    fontWeight: textFontWeight ?? theme.textFontWeight,
                    text: text,
                    x: (datum, ctx, opt)=>{
                        const parentNode = opt.mark?._product?.parent;
                        if (parentNode?.attribute?.data?.length) {
                            const point = parentNode.attribute.data[parentNode.attribute.data.length - 1].linePoints;
                            return point[point.length - 1]?.x;
                        }
                    },
                    y: (datum, ctx, opt)=>{
                        const parentNode = opt.mark?._product?.parent;
                        if (parentNode?.attribute?.data?.length) {
                            const point = parentNode.attribute.data[parentNode.attribute.data.length - 1].linePoints;
                            return point[point.length - 1]?.y;
                        }
                    }
                }
            });
        });
        return result;
    };
const getDefaultRegressionOptions = (lineConfig)=>({
        alpha: lineConfig?.confidenceLevel ?? 0.95
    });
const linearRegressionLine = generateRegressionLinePipe('linearRegressionLine', regressionLinear);
const lowessRegressionLine = generateRegressionLinePipe('lowessRegressionLine', regressionLowess);
const polynomialRegressionLine = generateRegressionLinePipe('polynomialRegressionLine', regressionPolynomial, (lineConfig)=>({
        ...getDefaultRegressionOptions(lineConfig),
        degree: lineConfig.degree ?? 2
    }));
const logisticRegressionLine = generateRegressionLinePipe('logisticRegressionLine', regressionLogistic);
export { generateRegressionLinePipe, linearRegressionLine, logisticRegressionLine, lowessRegressionLine, polynomialRegressionLine };

//# sourceMappingURL=linearRegressionLine.js.map