// SPDX-License-Identifier: AGPL-3.0-or-later
// SPDX-FileCopyrightText: 2020-2022 grommunio GmbH

import React, { Component } from "react";
import { withStyles } from "@mui/styles";
import PropTypes from "prop-types";
import TopBar from "../components/TopBar";
import LoadChart from "../components/LoadChart";
import MemoryChart from "../components/MemoryChart";
import CPUPieChart from "../components/CPUPieChart";
import MemoryPieChart from "../components/MemoryPieChart";
import SwapPieChart from "../components/SwapPieChart";
import DisksChart from "../components/DisksChart";
import CPULineChart from "../components/CPULineChart";
import ServicesChart from "../components/ServicesChart";
import AntispamStatistics from "../components/AntispamStatistics";
import { IconButton, Paper, Typography } from "@mui/material";
import { connect } from "react-redux";
import { fetchDashboardData } from "../actions/dashboard";
import { fetchAntispamData } from "../actions/antispam";
import { withTranslation } from "react-i18next";
import { fetchServicesData } from "../actions/services";
import Feedback from "../components/Feedback";
import { HelpOutline } from "@mui/icons-material";
import { fetchAboutData } from "../actions/about";
import About from "../components/About";
import { config } from '../config';

const styles = (theme) => ({
  root: {
    flex: 1,
    padding: theme.spacing(1),
    overflowY: "scroll",
    overflowX: "hidden",
  },
  dashboardLayout: {
    display: 'grid',
    [theme.breakpoints.up("xs")]: {
      gridTemplateColumns: "1fr 1fr",
      gridTemplateAreas: `"antispam antispam"
                          "headline headline"
                          "services services" 
                          "cpu      cpu"
                          "memory   memory"
                          "swap     swap  "
                          "disk     disk"`,
    }, 
    [theme.breakpoints.up("md")]: {
      gridTemplateColumns: '540px 1fr 1fr 1fr',
      gridTemplateAreas: `"antispam antispam antispam antispam"
                          "headline headline headline headline"
                          "services cpu      cpu      cpu     " 
                          "services memory   memory   memory  "
                          "services swap     swap     swap    "
                          "services disk     disk     disk    "`,
    },           
  },
  antispam: {
    gridArea: 'antispam',
  },
  services: {
    display: 'flex',
    flexDirection: 'column',
    gridArea: 'services',
  },
  cpu: {
    gridArea: 'cpu',
  },
  memory: {
    gridArea: 'memory',
  },
  disk: {
    gridArea: 'disk',
  },
  swap: {
    gridArea: 'swap',
  },
  headline: {
    display: 'grid',
  },
  donutAndLineChart: {
    display: 'grid',
    [theme.breakpoints.up("xs")]: {
      gridTemplateColumns: "1fr 1fr",
    },  
    [theme.breakpoints.up("sm")]: {
      gridTemplateColumns: '300px 1fr 1fr',
    },
  },
  donutChart: {
    [theme.breakpoints.up("xs")]: {
      gridColumn: '1 / 3',
    },   
    [theme.breakpoints.up("sm")]: {
      gridColumn: '1 / 2',
    },
  },
  lineChart: {
    display: 'flex',
    [theme.breakpoints.up("xs")]: {
      gridColumn: '1 / 3',
    }, 
    [theme.breakpoints.up("sm")]: {
      gridColumn: '2 / 4',
    },   
  },
  fullChart: {
    display: 'flex',
    [theme.breakpoints.up("xs")]: {
      gridColumn: '1 / 3',
    }, 
    [theme.breakpoints.up("sm")]: {
      gridColumn: '1 / 4',
    },  
  },
  toolbar: theme.mixins.toolbar,
  iconButton: {
    color: "black",
  },
  pageTitle: {
    margin: theme.spacing(2, 2, 1, 2),
  },
  subtitle: {
    margin: theme.spacing(0, 2, 2, 2),
  },
});

class Dashboard extends Component {
  componentDidMount() {
    const { fetch, fetchServices, fetchAntispam, fetchAbout } = this.props;
    fetch().catch((msg) => this.setState({ snackbar: msg }));
    fetchServices().catch((msg) => this.setState({ snackbar: msg }));
    if(config?.loadAntispamData) fetchAntispam().catch((msg) => this.setState({ snackbar: msg }));
    fetchAbout().catch((msg) => this.setState({ snackbar: msg }));
    this.fetchDashboard();
  }

  state = {
    snackbar: null,
  };

  fetchInterval = null;

  fetchDashboard() {
    this.fetchInterval = setInterval(() => {
      this.props.fetch().catch((msg) => this.setState({ snackbar: msg }));
    }, 10000);
  }

  componentWillUnmount() {
    clearInterval(this.fetchInterval);
  }

  render() {
    const {
      classes,
      t,
      cpuPercent,
      disks,
      memory,
      swap,
      swapPercent,
      load,
      statistics,
    } = this.props;
    const { snackbar } = this.state;

    return (
      <div className={classes.root}>
        <TopBar />
        <div className={classes.toolbar} />
        {config?.loadAntispamData && <Typography variant="h2" className={classes.pageTitle}>
          {t("Mail filter statistics")}
          <IconButton
            size="small"
            href="https://docs.grommunio.com/admin/administration.html#antispam"
            target="_blank"
          >
            <HelpOutline fontSize="small"/>
          </IconButton>
        </Typography>}
        {config?.loadAntispamData && <Typography variant="caption" className={classes.subtitle}>
          {t("mailfilter_sub")}
        </Typography>}
        <div className={classes.dashboardLayout}>
          {config?.loadAntispamData && <div className={classes.antispam}>
            <AntispamStatistics data={statistics}/>
          </div>}
          <div className={classes.services}>
            <ServicesChart/>
          </div>
          <div className={classes.headline}>
            <Typography variant="h2" className={classes.pageTitle}>
              {t("Performance")}
              <IconButton
                size="small"
                href="https://docs.grommunio.com/admin/administration.html#services"
                target="_blank"
              >
                <HelpOutline fontSize="small"/>
              </IconButton>
            </Typography>
            <Typography variant="caption" className={classes.subtitle}>
              {t("performance_sub")}
            </Typography>
          </div>
          <div className={classes.cpu}>
            <Paper elevation={1} className={classes.donutAndLineChart}>
              <div className={classes.donutChart}>
                <CPUPieChart cpuPercent={cpuPercent} />
              </div>
              <div className={classes.lineChart}>
                <CPULineChart cpuPercent={cpuPercent} />
              </div>
            </Paper>
          </div>
          <div className={classes.memory}>
            <Paper elevation={1} className={classes.donutAndLineChart}>
              <div className={classes.donutChart}>
                <MemoryPieChart memory={memory} />
              </div>
              <div className={classes.lineChart}>
                <MemoryChart memory={memory} />
              </div>
            </Paper>
          </div>
          <div className={classes.swap}>
            <Paper elevation={1} className={classes.donutAndLineChart}>
              {!!swapPercent && <div>
                <SwapPieChart swap={swap} swapPercent={swapPercent} />
              </div>}
              <div className={!swapPercent ? classes.fullChart : classes.lineChart}>
                <DisksChart disks={disks} />
              </div>
            </Paper>
          </div>
          <div className={classes.disk}>
            <LoadChart load={load} />
          </div>
        </div>
        <Typography variant="h2" className={classes.pageTitle}>
          {t("Versions")}
        </Typography>
        <About />
        <Feedback
          snackbar={snackbar}
          onClose={() => this.setState({ snackbar: "" })}
        />
      </div>
    );
  }
}

Dashboard.propTypes = {
  classes: PropTypes.object.isRequired,
  t: PropTypes.func.isRequired,
  fetch: PropTypes.func.isRequired,
  fetchServices: PropTypes.func.isRequired,
  fetchAntispam: PropTypes.func.isRequired,
  fetchAbout: PropTypes.func.isRequired,
  cpuPercent: PropTypes.array.isRequired,
  disks: PropTypes.array.isRequired,
  memory: PropTypes.array.isRequired,
  swap: PropTypes.array.isRequired,
  statistics: PropTypes.object.isRequired,
  swapPercent: PropTypes.number,
  load: PropTypes.array.isRequired,
};

const mapStateToProps = (state) => {
  return {
    ...state.dashboard.Dashboard,
    ...state.antispam,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    fetch: async () =>
      await dispatch(fetchDashboardData()).catch((error) =>
        Promise.reject(error)
      ),
    fetchServices: async () =>
      await dispatch(fetchServicesData()).catch((error) =>
        Promise.reject(error)
      ),
    fetchAntispam: async () =>
      await dispatch(fetchAntispamData()).catch((error) =>
        Promise.reject(error)
      ),
    fetchAbout: async () => await dispatch(fetchAboutData())
      .catch(err => Promise.reject(err)),
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(withTranslation()(withStyles(styles)(Dashboard)));