import * as React from "react";
import {createStyles, Theme, WithStyles, withStyles, WithTheme} from "@material-ui/core";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import {createApiRequestStore} from "../../../api/ApiRequestStore";
import {NewMonitoredAreaDialog} from "./components/NewMonitoredAreaDialog";
import MonitoredAreaCard from "./components/MonitoredAreaCard";
import {MonitoredArea, PvPanel} from "./MonitoredAreaPageTypes";
import {Autocomplete} from "@material-ui/lab";
import TextField from "@material-ui/core/TextField";
import Loader from "../../../common/Loader";
import {SiteDescription} from "../../../common/appRoutes";

const styles = (theme: Theme) =>
    createStyles({
        root: {
            flexGrow: 1,
        },
        paper: {
            padding: theme.spacing(2),
            textAlign: 'center',
            color: theme.palette.text.secondary,
        },
    });


type MonitoredAreaPageProps = {
    filteredIds?: number[]
    onSectionChange: (route: SiteDescription, params?: number[]) => void
} & WithStyles<typeof styles> & WithTheme


type MonitoredAreaPageState = {
    newMonitoredAreaDialogOpen: boolean
    monitoredAreaCards: MonitoredArea[]
    availablePvPanels: PvPanel[]
    filteredMonitoredAreas: MonitoredArea[]
    isLoadingData: boolean
}


class MonitoredAreasPage extends React.Component<MonitoredAreaPageProps, MonitoredAreaPageState> {
    requestStore = createApiRequestStore();

    readonly state: MonitoredAreaPageState = {
        newMonitoredAreaDialogOpen: false,
        monitoredAreaCards: [],
        availablePvPanels: [],
        filteredMonitoredAreas: [],
        isLoadingData: false,
    };

    private handleClickOpen = () => {
        this.setState({
            newMonitoredAreaDialogOpen: true
        })
    };

    private handleClose = () => {
        this.setState({
            newMonitoredAreaDialogOpen: false
        })
    };

    private handleSubmit = (newMonitoredArea: MonitoredArea) => {
        this.requestStore.createNewMonitoredArea(Object.assign(newMonitoredArea))
            .then(response => {
                if (response) {
                    this.handleClose();
                    this.loadMonitoredAreas(true);
                }
            }).catch((error) => {
            alert("something went wrong and new sensor was not created.")
        });
    };

    private loadMonitoredAreas = (isInitialLoad: boolean) => {
        this.setState({
            ...this.state,
            isLoadingData: true
        });
        this.requestStore.loadMonitoredAreas()
            .then(response => {
                this.setState({
                    ...this.state,
                    monitoredAreaCards: response.monitoredAreas.map((value): MonitoredArea => {
                        return {...value, isExpanded: false}
                    }),
                    availablePvPanels: response.availablePvPanels,
                    isLoadingData: false
                }, () => this.setFilteredAreasToState(this.state.monitoredAreaCards, isInitialLoad))
            })
            .catch(error => {
                alert("No monitored areas loaded for current user.");
                this.setState({
                    ...this.state,
                    isLoadingData: false
                });
            })
    };

    private setFilteredAreasToState = (reloadedMonitoredAreas: MonitoredArea[], isInitialLoad: boolean): void => {
        this.setState({
            ...this.state,
            filteredMonitoredAreas: this.expandedMonitoredAreas(reloadedMonitoredAreas, isInitialLoad)
        });
    };

    private expandedMonitoredAreas = (reloadedMonitoredAreas: MonitoredArea[], isFirstLoad: boolean): MonitoredArea[] => {
        const filteredMasByIds = this.props.filteredIds?.flatMap((v) => {
            return reloadedMonitoredAreas.filter((ma) => ma.id === v)
        });

        const previousStateFilteredMas = this.state.filteredMonitoredAreas;

        if (isFirstLoad) {
            return filteredMasByIds ? filteredMasByIds.map((ma): MonitoredArea => {
                return {
                    ...ma,
                    isExpanded: this.props.filteredIds ? ma.id === this.props.filteredIds[0] : false
                }
            }) : []
        } else {
            return previousStateFilteredMas.map((ma): MonitoredArea => {
                const reloadedMa = reloadedMonitoredAreas.find((maById) => maById.id === ma.id);
                return {
                    ...reloadedMa!,
                    isExpanded: ma.isExpanded
                }
            });
        }
    };

    private handleUpdate = (monitoredArea: MonitoredArea) => {
        this.requestStore.updateMonitoredArea(Object.assign(monitoredArea))
            .then(response => {
                this.loadMonitoredAreas(false);
            })
            .catch(error => {
                alert("Could not update monitored area")
            })
    };

    private handleOnChange = (event: any, values: any) => {
        this.setState({
            ...this.state,
            filteredMonitoredAreas: values
        })
    };

    private renderContent() {
        return <>
            <Grid item xs={6}>
                <div>
                    <Autocomplete
                        multiple
                        limitTags={2}
                        id="multiple-limit-tags"
                        options={this.state.monitoredAreaCards}
                        getOptionLabel={(option) => this.createOptionLabel(option)}
                        value={this.state.filteredMonitoredAreas}
                        onChange={this.handleOnChange}
                        getOptionSelected={(option, value) => option.id === value.id}
                        renderInput={(params) => (
                            <TextField {...params} variant="outlined" label="Monitored Area Description"
                                       placeholder="Monitored Areas" name={"description"}/>
                        )}
                    />
                </div>
            </Grid>
            {this.state.filteredMonitoredAreas?.map((value) => <MonitoredAreaCard key={value.id} cardData={value}
                                                                                  availablePvPanels={this.state.availablePvPanels}
                                                                                  handleUpdate={this.handleUpdate}
                                                                                  isExpanded={value.isExpanded}
                                                                                  handleExpanded={this.handleCardExpand}
                                                                                  onSectionChange={this.props.onSectionChange}
            />)
            }
        </>;
    }

    private createOptionLabel = (option: MonitoredArea) => {
        return `Area ${option.id}: '${option.description}' ${this.createInvInsLabel(option)}`;
    };

    private handleCardExpand = (updatedMa: MonitoredArea) => {
        this.setState({
            ...this.state,
            filteredMonitoredAreas: this.state.filteredMonitoredAreas.map((value): MonitoredArea => {
                if (value.id === updatedMa.id) {
                    return {...value, isExpanded: !value.isExpanded}
                } else return value
            })
        })
    };


    private createInvInsLabel = (option: MonitoredArea): string | undefined => {
        if (option.instrumentId === null || undefined && option.inverterId === null || undefined) {
            return ""
        } else {
            const instrumentId = option.instrumentId ? `Sensor ${option.instrumentId}` : "";
            const inverterId = option.inverterId ? `, Inverter ${option.inverterId}` : "";
            return `monitored by: (${instrumentId}${inverterId})`
        }
    };

    componentDidMount(): void {
        this.loadMonitoredAreas(true)
    }

    render() {
        return <div className={this.props.classes.root}>
            <Grid container spacing={3}>
                <Grid item xs={3}>
                    <div>
                        <Button variant="outlined" color="primary" onClick={this.handleClickOpen}>
                            New Monitored Area
                        </Button>
                        <NewMonitoredAreaDialog dialogOpen={this.state.newMonitoredAreaDialogOpen}
                                                handleSubmit={this.handleSubmit} handleClose={this.handleClose}/>
                    </div>
                </Grid>
                {this.state.isLoadingData ? <Grid item sm={12} xs={12}><Loader/></Grid> : this.renderContent()}
            </Grid>
        </div>
    }
}


export default withStyles(styles, {withTheme: true})(MonitoredAreasPage);