import React from "react";
import * as d3Shape from "d3-shape";
import { scaleTime, scaleLinear } from "d3-scale";
import * as d3ScaleChromatic from "d3-scale-chromatic";
import { Interval } from "date-fns";
interface DateData {
  data: number | null;
  date: string;
}

export const LineGraph: React.FC<{
  interval: Interval;
  data: DateData[][];
  width: number;
  height: number;
  highlightIntervals: {
    interval: Interval;
    heightValue: number;
    changePercentage: number | null;
  }[];
  maxChangePercentage: number;
  stroke: string;
}> = ({
  data,
  interval,
  width,
  height,
  highlightIntervals,
  maxChangePercentage,
  stroke,
}) => {
  const leftMargin = 50;
  const bottomMargin = 20;
  const topMargin = 20;
  const contentWidth = width - leftMargin;
  const contentHeight = height - bottomMargin;

  const line = data[0];
  const minValue = Math.min(...line.map((d) => d.data ?? 0), 0);
  const maxValue = Math.max(...line.map((d) => d.data ?? 0));

  const scaleX = scaleTime()
    .domain([interval.start, interval.end])
    .range([0, contentWidth]);

  const scaleY = scaleLinear()
    .domain([minValue, maxValue])
    .range([contentHeight, 0]);

  const getLine = d3Shape
    .line<DateData>()
    .x((d) => scaleX(new Date(d.date)))
    .y((d) => scaleY(d.data ?? 0))
    .defined((d) => d.data != null)
    .curve(d3Shape.curveLinear);

  const tickSize = 2;

  return (
    <svg className="line-graph" viewBox={`0 0 ${width} ${height + topMargin}`}>
      <g transform={`translate(0, ${topMargin})`}>
        <g transform={`translate(${leftMargin}, 0)`}>
          {highlightIntervals.map(
            ({ interval, heightValue, changePercentage }, i) => {
              const v =
                1 - ((changePercentage ?? 0) / maxChangePercentage + 1) / 2;
              const color = d3ScaleChromatic.interpolateGreys(v);
              const width = scaleX(interval.end) - scaleX(interval.start) - 8;
              const height = scaleY(maxValue - heightValue);
              const textColor = v > 0.5 ? "red" : "lime";
              if (!heightValue) return null;
              return (
                <g
                  transform={`translate(${scaleX(interval.start)}, ${scaleY(
                    heightValue
                  )})`}
                  key={i}
                >
                  <rect
                    x={0}
                    width={width}
                    y={0}
                    height={height}
                    fill={color}
                    opacity={0.8}
                  />
                  {changePercentage != null && (
                    <text
                      style={{
                        fontSize: "10px",
                        textAnchor: "middle",
                      }}
                      fill={textColor}
                      transform={`translate(${width / 2}, ${height / 2})`}
                    >
                      {Intl.NumberFormat("en", {
                        style: "percent",
                        signDisplay: "always",
                      }).format((changePercentage ?? 0) / 100)}
                    </text>
                  )}
                </g>
              );
            }
          )}
          {data.map((line, i) => (
            <path
              d={getLine(line) ?? ""}
              stroke={stroke}
              fill="transparent"
              strokeWidth={2}
              key={i}
            />
          ))}
          <g
            transform={`translate(0, ${
              contentHeight + bottomMargin - tickSize - 4
            })`}
          >
            {scaleX.ticks(line.length).map((date, i) => (
              <g transform={`translate(${scaleX(date)}, 0)`} key={i}>
                <line
                  y1={-tickSize}
                  y2={-2 * tickSize}
                  stroke="white"
                  strokeWidth={0.5}
                />
                {i % 2 === 1 && (
                  <text
                    style={{
                      fontSize: "8px",
                      color: "white",
                      textAnchor: "middle",
                      transform: `translateY(${tickSize + 4}px)`,
                    }}
                    fill="white"
                  >
                    {Intl.DateTimeFormat(undefined, {
                      month: "numeric",
                      day: "numeric",
                    }).format(date)}
                  </text>
                )}
              </g>
            ))}
          </g>
        </g>

        <g transform={`translate(-${tickSize + 4}, 0)`}>
          {scaleY.ticks(3).map((value, i) => (
            <g transform={`translate(${leftMargin}, ${scaleY(value)})`} key={i}>
              <line x2={tickSize} stroke="white" strokeWidth={0.5} />
              <text
                style={{
                  fontSize: "10px",
                  color: "white",
                  textAnchor: "end",
                  transform: `translateX(-${tickSize + 4}px)`,
                }}
                fill="white"
              >
                {Intl.NumberFormat("en", { notation: "compact" }).format(value)}
              </text>
            </g>
          ))}
        </g>
      </g>
    </svg>
  );
};
