<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}
                        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}
                        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])} />
        {/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>