import React from "react";
import * as d3 from 'd3';
import {brushX, event, ScaleTime} from 'd3';
import {select} from "d3-selection";
import {DataPoint, Margins, PerformanceRatioData, Size} from "../MySitePageTypes";
import {
    appendBrushXAxisTicks,
    appendXAxisTicks,
    appendY1axisDescription,
    appendY1AxisTicks,
    filterData,
    graphColors,
    legendOffset,
    transformXYvaluesToLines
} from "./chartHelpers";

type Props = {
    performanceRatio: PerformanceRatioData,
    graphSize: Size
    brushSize: Size
    margins: Margins
}

type State = {
    minT: Date,
    maxT: Date
}


class PerformanceRatioChart extends React.Component<Props> {
    graph: SVGSVGElement | undefined;
    brushRef: SVGGElement | undefined;

    readonly state: State = {
        minT: this.props.performanceRatio.minT,
        maxT: this.props.performanceRatio.maxT
    };

    private renderGraph = () => {
        const graph = select(this.graph!);

        const filteredData = this.filterData();

        const x = this.computeXaxis(filteredData.minT, filteredData.maxT);
        const y = this.computeYaxis(filteredData.graphData, this.props.graphSize.height);
        const performanceRatioLineChart = transformXYvaluesToLines(x, y);

        appendXAxisTicks(graph, x, this.props.graphSize, this.props.margins);
        appendY1AxisTicks(graph, y, this.props.margins);
        return [this.renderPerformanceRatioLines(performanceRatioLineChart, filteredData.graphData)]
    };

    private renderBrush = () => {
        const brush = select(this.brushRef!);
        const x = this.computeXaxis(this.props.performanceRatio.minT, this.props.performanceRatio.maxT);
        const y = this.computeYaxis(this.props.performanceRatio.graphData, this.props.brushSize.height);
        const performanceRatioLineChart = transformXYvaluesToLines(x, y);
        this.applyBrush(brush, x);
        appendBrushXAxisTicks(brush, x, this.props.brushSize, this.props.margins);
        return [
            this.renderPerformanceRatioLines(performanceRatioLineChart, this.props.performanceRatio.graphData)
        ]
    };

    private applyBrush = (brush: d3.Selection<SVGGElement, unknown, null, undefined>, x: ScaleTime<number, number>) => {
        brush
            .call(brushX()
                .extent([[this.props.margins.left * 3, 0], [this.props.brushSize.width - 100, 100]])
                .on("end", this.brushed(x)));
    };

    private brushed = (timeScale: ScaleTime<number, number>) => {
        return () => {
            const [newMinT, newMaxT] = event.selection ? event.selection.map((d: Date) => timeScale.invert(d)) : [this.state.minT, this.state.maxT];
            this.onBrushChange(newMinT, newMaxT);
        };
    };

    private onBrushChange = (newMinT: Date, newMaxT: Date) => {
        this.setState({
            ...this.state,
            minT: newMinT,
            maxT: newMaxT
        })
    };

    private filterData = (): PerformanceRatioData => {
        return {
            ...this.props.performanceRatio,
            minT: this.state.minT,
            maxT: this.state.maxT,
            graphData: filterData(this.props.performanceRatio.graphData, this.state.minT, this.state.maxT)
        };
    };

    private computeYaxis = (data: DataPoint[], height: number) => {
        return d3.scaleLinear()
            .domain([0, d3.max(data.map(it => it.value))!])
            .range([height - this.props.margins.bottom, 0]);
    };

    private computeXaxis = (minT: Date, maxT: Date) => {
        return d3.scaleTime()
            .domain([minT, maxT])
            .range([this.props.margins.left * 3, this.props.graphSize.width - 100]);
    };

    private renderPerformanceRatioLines = (lineChart: (graphData: DataPoint[]) => string | null, filteredData: DataPoint[]) => {
        return <g key={"key-prLines"}>
            <path id={`real-energy-area`}
                  key={`real-energy-area`}
                  d={lineChart(filteredData)!}
                  style={{
                      stroke: graphColors[0].stroke,
                      strokeWidth: 3,
                      fill: "none"
                  }}
            />
        </g>

    };

    componentDidMount() {
        this.renderGraph();
        this.renderBrush();
    }


    render() {
        return <>
            <svg ref={(graph: SVGSVGElement) => this.graph = graph} width={this.props.graphSize.width}
                 height={this.props.graphSize.height}>
                {this.renderGraph()}
                {appendY1axisDescription("Performance Ratio (%)", 0, this.props.graphSize.height / 2)}
            </svg>
            <svg
                ref={(brushRef: SVGSVGElement) => this.brushRef = brushRef}
                width={this.props.brushSize.width}
                height={this.props.brushSize.height}
            >
                {this.renderBrush()}
            </svg>
        </>
    }


}

export default PerformanceRatioChart