<script lang="ts">
 //@ts-nocheck

 import { line, curveLinear, Delaunay, range, scaleLinear } from 'd3';

 export let data;

 const marginTop = 30; // the top margin, in pixels
 const marginRight = 30; // the right margin, in pixels
 const marginBottom = 30; // the bottom margin, in pixels
 const marginLeft = 100; // the left margin, in pixels
 const inset = 0; // inset the default range, in pixels
 const width = 600; // the outer width of the chart, in pixels
 const height = 400; // the outer height of the chart, in pixels
 const xLabel = ''; // a label for the y-axis
 const yLabel = 'Résultat net'; // a label for the y-axis
 const xFormat = ''; // a format specifier string for the y-axis
 const yFormat = '€'; // a format specifier string for the y-axis
 const horizontalGrid = true; // show horizontal grid lines
 const verticalGrid = true; // show vertical grid lines
 const colors = ["#b81111", "#ffbf00"]; // fill color for dots && number of colors in fill array MUST match number of subsets in data
 const showDots = false; // whether dots should be displayed
 const dotsFilled = true; // whether dots should be filled or outlined
 const r = 0; // (fixed) radius of dots, in pixels
 const strokeWidth = 1; // stroke width of line, in pixels
 const strokeOpacity = [1]; // stroke opacity of line
 const tooltipBackground = 'white'; // background color of tooltip
 const tooltipTextColor = 'black'; // text color of tooltip
 const strokeLinecap = 'round'; // stroke line cap of the line
 const strokeLinejoin = 'round'; // stroke line join of the line
 const xScalefactor = width / 180; //y-axis number of values
 const yScalefactor = height / 40; //y-axis number of values
 const curve = curveLinear; // method of interpolation between points
 const xType = scaleLinear; // type of x-scale
 const insetTop = 50; // inset from top
 const insetRight = inset; // inset from right
 const insetBottom = inset; // inset fro bottom
 const insetLeft = inset; // inset from left
 const xRange = [marginLeft + insetLeft, width - marginRight - insetRight]; // [left, right]
 const yType = scaleLinear; // type of y-scale
 const yRange = [height - marginBottom - insetBottom, marginTop + insetTop]; // [bottom, top]

 let x: string, y:string, dotInfo, lines, xVals = [], yVals = [], points = [], subsets = [], colorVals = [];

 let I, xScale, gaps, cleanData, xDomain, yDomain, yScale, niceY, chartLine, pointsScaled, delaunayGrid, voronoiGrid, xTicks, xTicksFormatted, yTicks

 $: {
     // For a single set of data
     xVals = []
     yVals = []
     if (!('data' in data[0])) {
         x = Object.keys(data[0])[0];
         y = Object.keys(data[0])[1];
         xVals = data.map((el: Record<string, any>) => el[x]);
         yVals = data.map((el: Record<string, any>) => el[y]);
         colorVals = data.map((_) => 0);
         points = data.map((el) => ({
             x: el[x],
             y: el[y],
             color: 0
         }));
     }
     // For data with subsets (NOTE: expects 'id' and 'data' keys)
     else {
         x = Object.keys(data[0]?.data[0])[0];
         y = Object.keys(data[0]?.data[0])[1];
         data.forEach((subset, i) => {
             subset.data.forEach((coordinate) => {
                 xVals.push(coordinate[x]);
                 yVals.push(coordinate[y]);
                 colorVals.push(i);
                 points.push(
                     {
                         x: coordinate[x],
                         y: coordinate[y],
                         color: i
                 });
             });
             subsets.push(subset.id);
         });
     }

     I = range(xVals.length);
     gaps = (_d, i) => !isNaN(xVals[i]) && !isNaN(yVals[i]);
     cleanData = points.map(gaps);

     xDomain = [xVals[0], xVals[xVals.length - 1]];
     yDomain = [Math.min(...yVals), Math.max(...yVals)];
     xScale = xType(xDomain, xRange);
     yScale = yType(yDomain, yRange);
     niceY = scaleLinear().domain([Math.min(...yVals), Math.max(...yVals)]).nice();

     chartLine = line()
         .defined(i => cleanData[i])
         .curve(curve)
         .x(i => xScale(xVals[i]))
         .y(i => yScale(yVals[i]));

     lines = [];
     colors.forEach((_color, j) => {
         const filteredI = I.filter((_el, i) => colorVals[i] === j);
         lines.push(chartLine(filteredI));
     });
     console.log("lines", lines)

     pointsScaled = points.map((el) => [xScale(el.x), yScale(el.y), el.color]);
     delaunayGrid = Delaunay.from(pointsScaled);
     voronoiGrid = delaunayGrid.voronoi([0, 0, width, height]);

     xTicks = xScale.ticks(xScalefactor);
     xTicksFormatted = xTicks.map((el) => el)
     yTicks = niceY.ticks(yScalefactor);
 }
</script>

<div class="chart-container">
    <svg {width} {height} viewBox="0 0 {width} {height}"
         cursor='crosshair'
        on:mouseout="{() => dotInfo = null}"
             on:blur="{() => dotInfo = null}"
    >
        <!-- Dots (if enabled) -->
        {#if showDots && !dotInfo}
            {#each I as i}
                <g class='dot' pointer-events='none'>
                    <circle
                        cx={xScale(xVals[i])}
                        cy={yScale(yVals[i])}
                        r={r}
                        stroke={colors[colorVals[i]]}
                        fill={dotsFilled ? colors[colorVals[i]] : 'none'}
                    />
                </g>
            {/each}
        {/if}
        <!-- Chart lines -->
        {#each lines as subsetLine, i}
            <g class='chartlines' pointer-events='none'>
                {#if dotInfo && false}
                    <path class="line" fill='none' stroke-opacity={points[dotInfo[1]].color === i ? '1' : '0.1'} stroke={colors[i]} d={subsetLine} stroke-width={strokeWidth} stroke-linecap={strokeLinecap} stroke-linejoin={strokeLinejoin}/>
                    <circle cx={xScale(points[dotInfo[1]].x)} cy={yScale(points[dotInfo[1]].y)} r={r} stroke={colors[points[dotInfo[1]].color]} fill={dotsFilled} />
                {:else}
                    <path class="line" fill='none' stroke={colors[i]} d={subsetLine}
                          stroke-opacity={strokeOpacity[i]} stroke-width={strokeWidth} stroke-linecap={strokeLinecap} stroke-linejoin={strokeLinejoin} />
                {/if}
            </g>
        {/each}
        <!-- Y-axis and horizontal grid lines -->
        <g class="y-axis" transform="translate({marginLeft}, 0)" pointer-events='none'>
            <path class="domain" stroke="black" d="M{insetLeft}, {marginTop} V{height - marginBottom + 6}"/>
            {#each yTicks as tick}
                <g class="tick" transform="translate(0, {yScale(tick)})">
                    <line class="tick-start" x1={insetLeft - 6} x2={insetLeft}/>
                    {#if horizontalGrid}
                        <line class="tick-grid" x1={insetLeft} x2={width - marginLeft - marginRight}/>
                    {/if}
                    <text x="-10" y="5">{tick + yFormat}</text>
                </g>
            {/each}
            <text text-anchor="middle" x="0" y={marginTop - 10}>{yLabel}</text>
        </g>
        <!-- X-axis and vertical grid lines -->
        <g class="x-axis" transform="translate(0,{height - marginBottom - insetBottom})" pointer-events='none'>
            <path class="domain" stroke="black" d="M{marginLeft},0.5 H{width - marginRight}"/>
            {#each xTicks as tick, i}
                <g class="tick" transform="translate({xScale(tick)}, 0)">
                    <line class="tick-start" stroke='black' y2='6' />
                    {#if verticalGrid}
                        <line class="tick-grid" y2={-height + insetTop+ marginTop} />
                    {/if}
                    <text font-size='8px' x={-marginLeft/4} y="20">{xTicksFormatted[i] + xFormat}</text>
                </g>
            {/each}
            <text x={width - marginLeft - marginRight - 40} y={marginBottom}>{xLabel}</text>
        </g>

        {#each pointsScaled as point, i}
            <path
                stroke="none"
                fill-opacity="0"
                class="voronoi-cell"
                d={voronoiGrid.renderCell(i)}
                on:mouseover="{(e) => dotInfo = [point, i, e] }"
                on:focus="{(e) => dotInfo = [point, i, e] }"
            ></path>
        {/each}
    </svg>
</div>
<!-- Tooltip -->
{#if dotInfo}
    <div class="tooltip" style='position:absolute; left:{dotInfo[2].pageX + 12}px; top:{dotInfo[2].pageY + 12}px; pointer-events:none; background-color:{tooltipBackground}; color:{tooltipTextColor}'>
        {points[dotInfo[1]].x}: {points[dotInfo[1]].y.toFixed(2)}{yFormat}
    </div>
{/if}

<style>
 .chart-container {
     justify-content: center;
     align-items: center;
     margin-top: 50px;
     margin-left: 8
     0px;
 }
 svg {
     max-width: 100%;
     height: auto;
     height: "intrinsic";
     margin: auto;
 }
 path {
     fill: "green"
 }
 .y-axis {
     font-size: "10px";
     font-family: sans-serif;
     text-anchor: "end";
 }
 .x-axis {
     font-size: "10px";
     font-family: sans-serif;
     text-anchor: "end";
 }
 .tick text { font-size: 80%; fill: white !important }
 .tick {
     opacity: 1;
 }
 .tick-start {
     stroke: black;
     stroke-opacity: 1;
 }
 .tick-grid {
     stroke: black;
     stroke-opacity: 0.2;
     font-size: "11px";
     color: black;
 }
 .tick text {
     fill: black;
 }

 .y-axis .tick text {
     text-anchor: end !important;
 }

 @media (prefers-color-scheme: dark) {
     .y-axis text { fill: white; }
     .x-axis text { fill: white; }
     .tick-start {
         stroke: white;
     }
     .tick-grid {
         stroke: white;
     }
     .tick text {
         fill: white;
     }
     .domain { stroke: white }
 }


 .tooltip{
     border-radius: 5px;
     padding: 5px;
     box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px, rgba(0, 0, 0, 0.3) 0px 7px 13px -3px, rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
     opacity: 1;
 }
</style>