import React from "react";
import {addHours, subHours} from "date-fns";
import {aqiSensorColorGradient, pmSensorColorGradient} from "../../common/ColorGradient";
import {BLACK_CSS, formatTimestamp, range, roundTo} from "../../common/Helpers";
import {getPMHistory} from "../../common/FrostApiProxy";
import {Typography} from "@material-ui/core";
import {CartesianGrid, Legend, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis} from "recharts";
import {PopupDataInfo} from "./Popup";
import {PopupGrid, PopupGridItem} from "./PopupGrid";

type DateValue = {
    timestamp: number;
    value: number;
}

type PMPopupState = {
    chartData?: DateValue[];
    isLoading: boolean;
    fromDate: Date,
    toDate: Date,
}
type PMPopupProps = {
    info: PopupDataInfo;
}

export class PMPopupContent extends React.Component<PMPopupProps, PMPopupState> {
    constructor(props: PMPopupProps) {
        super(props);

        let {fromDate, toDate} = this.props.info.dateFilter;
        if (!fromDate && !toDate) {
            toDate = new Date();
            fromDate = subHours(toDate, 24);
        } else if (!fromDate && toDate) {
            fromDate = subHours(toDate, 24);
        } else if (fromDate && !toDate) {
            toDate = addHours(fromDate, 24);
        }

        this.state = {
            isLoading: false,
            fromDate: fromDate!,
            toDate: toDate!,
        };

    }

    componentDidMount() {
        if (!this.state.isLoading && !this.state.chartData) {
            this.loadHistoryData();
        }
    }

    private getGridItems(): PopupGridItem[] {
        const {pmInfo} = this.props.info;
        const textColor = pmSensorColorGradient.getColorAtAsCssHex(
            pmInfo?.pm,
            BLACK_CSS,
            true
        );
        const aqiTextColor =  aqiSensorColorGradient.getColorAtAsCssHex(
            pmInfo?.aqiValue,
            BLACK_CSS,
            true
        );
        const averageStr = this.props.info.isFiltered ? " Average" : "";
        return [
            {key: "Sensor Type", value: "SDS 011"},
            {key: "Description", value: pmInfo?.description},
            {key: "Longitude", value: pmInfo?.longitude},
            {key: "Latitude", value: pmInfo?.latitude},
            {key: "PM2.5" + averageStr, value: roundTo(pmInfo?.pm), textColor, unit: "µg/m³"},
            {key: "AQI", value: `${roundTo(pmInfo?.aqiValue)} (${pmInfo?.aqiRange?.name})`, textColor:  aqiTextColor},
        ];
    }

    private getChartTitle(): string {
        const {fromDate, toDate} = this.props.info.dateFilter;
        const parts = [];
        if (fromDate || toDate) {
            const dateTimeFormat = "dd.MM.yyyy HH:mm";
            const dayFormat = "dd.MM.yyyy";
            if (fromDate && toDate && fromDate.getHours() === 0 && toDate.getHours() === 23) {
                parts.push(`for ${formatTimestamp(this.state.fromDate.getTime(), dayFormat)}`);
            } else {
                parts.push(`from ${formatTimestamp(this.state.fromDate.getTime(), dateTimeFormat)}`);
                parts.push(`to ${formatTimestamp(this.state.toDate.getTime(), dateTimeFormat)}`);
            }
        }
        const period = parts.length ? parts.join(" ") : "for the last 24 hours";
        return `Emission rates ${period}`;
    }

    private loadHistoryData() {
        this.setState({isLoading: true});
        setTimeout(() => {
            const {id} = this.props.info.pmInfo!;
            const {fromDate, toDate} = this.state;
            getPMHistory(+id, fromDate!, toDate!)
                .then(data => {
                    this.setState({
                        chartData: data.map(it => ({timestamp: it.phenomenonTime.getTime(), value: it.result})),
                        isLoading: false
                    });
                });
        }, 100);
    }

    private getMinMaxValues() {
        const minValue = this.state.chartData ? Math.min(...this.state.chartData.map(d => d.value)) : 0;
        const maxValue = this.state.chartData ? Math.max(...this.state.chartData.map(d => d.value)) : 0;

        return {minValue, maxValue};
    }

    render() {
        const {minValue, maxValue} = this.getMinMaxValues();
        return <div>
            <PopupGrid items={this.getGridItems()}/>
            <div style={{marginTop: 10}}>
                <Typography variant={"h6"}>{this.getChartTitle()}</Typography>
                <div style={{textAlign: "center"}}>
                    {this.state.isLoading ? "Loading..." :
                        <ResponsiveContainer className={"area-chart-container"} height={300}>
                            <LineChart data={this.state.chartData}>
                                <defs>
                                    <linearGradient id="chartGradient" x1="0" y1="0" x2="0" y2="1">
                                        {range(0, 1, 10).map(v =>
                                            <stop key={`range-${v}`} offset={v}
                                                  stopColor={pmSensorColorGradient?.getColorAtAsCssHex(
                                                      (1 - v) * (maxValue - minValue) + minValue, undefined, true
                                                  )}
                                                  stopOpacity={1}/>
                                        )}
                                    </linearGradient>
                                </defs>
                                <CartesianGrid strokeDasharray="3 3"/>
                                <XAxis dataKey="timestamp" type={"number"}
                                       allowDataOverflow
                                       domain={["dataMin", "dataMax"]}
                                       tickFormatter={timestamp => formatTimestamp(timestamp)}/>
                                <YAxis domain={[0, (dataMax: number) => Math.max(dataMax, 100)]}
                                       tickCount={5}
                                       tickFormatter={pm => roundTo(pm)?.toString() || ""}/>
                                <Legend/>
                                <Tooltip
                                    labelFormatter={(timestamp) => formatTimestamp(timestamp, "dd.MM.yyyy HH:mm")}
                                    formatter={(pm: number) => pm + " µg/m³"}
                                />
                                <Line
                                    dataKey={"value"}
                                    dot={false}
                                    name={"PM2.5"}
                                    strokeWidth={2}
                                    stroke={"url(#chartGradient)"}
                                    // @ts-ignore
                                    activeDot={({cx, cy, payload}) =>
                                        (<circle cx={cx}
                                                 cy={cy}
                                                 r={5}
                                                 stroke={"white"}
                                                 strokeWidth={1}
                                                 fill={pmSensorColorGradient.getColorAtAsCssHex(payload.value, "black", true)}
                                        />)
                                    }
                                />
                            </LineChart>
                        </ResponsiveContainer>
                    }
                </div>
            </div>
        </div>;
    }
}
