import { isNullish } from "remeda";
import { array, clamper, regressionPolynomial } from "@visactor/vutils";
import { defaultRegressionLineColor, getAlphaByConfidenceLevel } from "./common.js";
const columnPolynomialRegressionLine = (spec, context)=>{
    const result = {
        ...spec
    };
    const { advancedVSeed } = context;
    const { chartType, regressionLine } = advancedVSeed;
    const lineTheme = advancedVSeed.config[chartType]?.regressionLine;
    if (!regressionLine || !regressionLine.polynomialRegressionLine) return result;
    const lineList = array(regressionLine.polynomialRegressionLine);
    if (!result.extensionMark) result.extensionMark = [];
    lineList.forEach((line, lineIndex)=>{
        if (false === line.enable) return;
        const theme = lineTheme.linearRegressionLine ?? {};
        const { color, lineWidth, lineDash, text, textColor, textFontSize, textFontWeight, confidenceIntervalOpacity, confidenceLevel = 0.95, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, confidenceIntervalVisible = theme.confidenceIntervalVisible } = line;
        const childrenMarks = [];
        result.extensionMark.push({
            type: 'group',
            interactive: false,
            zIndex: 500,
            name: `polynomialRegressionLine-${lineIndex}`,
            dataId: spec.data?.id,
            style: {
                data: (datum, ctx)=>{
                    const vchart = ctx.vchart;
                    const chart = vchart.getChart();
                    const s = chart.getAllSeries()[0];
                    if (s) {
                        const rect = s.getRegion().getLayoutRect();
                        if (0 === rect.width || 0 === rect.height) return null;
                        const yClamper = clamper(0, 0 + rect.height);
                        const data = s.getViewData()?.latestData;
                        const fieldX = s.fieldX?.[0];
                        const fieldY = s.fieldY?.[0];
                        const xValues = s.getRawDataStatisticsByField(fieldX).values;
                        const degree = line.degree ?? 2;
                        const minPoints = degree + 1;
                        if (!fieldX || !fieldY || !data || data.length < minPoints || xValues.length < minPoints) return null;
                        const { confidenceInterval, evaluateGrid } = regressionPolynomial(xValues.map((xVal, index)=>{
                            const filteredData = data.filter((d)=>d[fieldX] === xVal);
                            return {
                                x: index,
                                y: Math.max(...filteredData.map((d)=>d[fieldY]))
                            };
                        }), void 0, void 0, {
                            degree: line.degree ?? 2,
                            alpha: getAlphaByConfidenceLevel(confidenceLevel)
                        });
                        const N = xValues.length;
                        const xAxisHelper = s.getXAxisHelper();
                        const halfBandWidth = xAxisHelper ? xAxisHelper.getBandwidth(0) / 2 : 0;
                        const lineData = evaluateGrid(N);
                        const linePoints = lineData.map((datum, index)=>{
                            const d = {
                                [fieldX]: xValues[index],
                                [fieldY]: datum.y
                            };
                            return {
                                x: s.dataToPositionX(d) + halfBandWidth,
                                y: yClamper(s.dataToPositionY(d))
                            };
                        });
                        const result = {
                            linePoints,
                            color: s.getOption().globalScale.getScale('color')?.scale(s.getSeriesKeys()[0])
                        };
                        if (confidenceIntervalVisible) {
                            const intervalData = confidenceInterval(N);
                            result.areaPoints = intervalData.map((datum, index)=>{
                                const d = {
                                    [fieldX]: xValues[index],
                                    [fieldY]: datum.lower
                                };
                                return {
                                    x: s.dataToPositionX(d) + halfBandWidth,
                                    y: yClamper(s.dataToPositionY(d)),
                                    y1: yClamper(s.dataToPositionY({
                                        [fieldY]: datum.upper
                                    }))
                                };
                            });
                        }
                        return result;
                    }
                    return null;
                }
            },
            children: childrenMarks
        });
        if (confidenceIntervalVisible) childrenMarks.push({
            type: 'area',
            interactive: false,
            zIndex: 500,
            dataId: spec.data?.id,
            style: {
                stroke: false,
                lineWidth: lineWidth ?? theme.lineWidth,
                lineDash: lineDash ?? theme.lineDash,
                fillOpacity: confidenceIntervalOpacity ?? theme.confidenceIntervalOpacity,
                fill: color ?? defaultRegressionLineColor,
                points: (datum, ctx, opt)=>{
                    const parentNode = opt.mark?._product?.parent;
                    if (parentNode?.attribute?.data) return parentNode.attribute.data.areaPoints;
                    return [];
                }
            }
        });
        childrenMarks.push({
            type: 'line',
            interactive: false,
            zIndex: 500,
            dataId: spec.data?.id,
            style: {
                lineWidth: lineWidth ?? theme.lineWidth,
                lineDash: lineDash ?? theme.lineDash,
                stroke: color ?? defaultRegressionLineColor,
                shadowBlur: shadowBlur ?? theme.shadowBlur,
                shadowColor: shadowColor ?? theme.shadowColor,
                shadowOffsetX: shadowOffsetX ?? theme.shadowOffsetX,
                shadowOffsetY: shadowOffsetY ?? theme.shadowOffsetY,
                points: (datum, ctx, opt)=>{
                    const parentNode = opt.mark?._product?.parent;
                    if (parentNode?.attribute?.data) return parentNode.attribute.data.linePoints;
                    return [];
                }
            }
        });
        if (!isNullish(text)) childrenMarks.push({
            type: 'text',
            interactive: false,
            zIndex: 500,
            dataId: spec.data?.id,
            dataKey: ()=>`polynomialRegressionLine-label-${lineIndex}`,
            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?.linePoints) {
                        const points = parentNode.attribute.data.linePoints;
                        return points[points.length - 1]?.x;
                    }
                },
                y: (datum, ctx, opt)=>{
                    const parentNode = opt.mark?._product?.parent;
                    if (parentNode?.attribute?.data?.linePoints) {
                        const points = parentNode.attribute.data.linePoints;
                        return points[points.length - 1]?.y;
                    }
                }
            }
        });
    });
    return result;
};
export { columnPolynomialRegressionLine };

//# sourceMappingURL=columnRegressionLine.js.map