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

import React, { PureComponent } from 'react';
import { FormControl, Grid,
  IconButton,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableRow,
  TableSortLabel,
  Tooltip,
  Typography } from '@mui/material';
import { CleaningServices, DoNotDisturbOn, Sync as SyncIcon, Delete } from '@mui/icons-material';
import { withStyles } from '@mui/styles';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';
import { parseUnixtime } from '../../utils';
import { fetchUserSync } from '../../actions/users';
import { connect } from 'react-redux';
import PasswordSafetyDialog from '../Dialogs/PasswordSafetyDialog';
import { cancelRemoteWipe, engageRemoteDelete, engageRemoteWipe, engageResync } from '../../actions/sync';
import Feedback from '../Feedback';

const styles = theme => ({
  form: {
    width: '100%',
    marginTop: theme.spacing(4),
  },
  headline: {
    margin: theme.spacing(0, 0, 2, 0),
  },
  listItem: {
    padding: theme.spacing(1, 0, 1, 0),
  },
  listTextfield: {
    flex: 1,
  },
});

class Sync extends PureComponent {

  componentDidMount() {
    const { fetch, domainID, userID } = this.props;
    const { orderBy, type } = this.state; 
    fetch(domainID, userID)
      .then(this.handleSort(orderBy, type, false))
      .catch(err => console.error(err));
  }

  state = {
    snackbar: '',
    sortedDevices: null,
    order: 'asc',
    orderBy: 'pid',
    type: 'int',
    wipingID: '',
  };

  columns = [
    { label: "Device ID", value: "deviceid" },
    { label: "Device user", value: "deviceuser" },
    { label: "Device Type / Agent", value: "devicetype" },
    { label: "First sync", value: "firstsynctime", type: 'int' },
    { label: "Last update", value: "lastudpatetime", type: 'int' },
    { label: "AS version", value: "asversion" },
    { label: "Folders", value: "foldersSynced", type: 'int' },
    { label: "Wipe status", value: "wipeStatus", type: 'int' },
  ];

  handleSort = (attribute, type, switchOrder) => () => {
    const sortedDevices = [...this.props.sync];
    const { order: stateOrder, orderBy } = this.state;
    const order = orderBy === attribute && stateOrder === "asc" ? "desc" : "asc";
    if((switchOrder && order === 'asc') || (!switchOrder && stateOrder === 'asc')) {
      sortedDevices.sort((a, b) =>
        type !== 'int' ? a[attribute].localeCompare(b[attribute]) : a[attribute] - b[attribute]
      );
    } else {
      sortedDevices.sort((a, b) => 
        type !== 'int' ? b[attribute].localeCompare(a[attribute]) : b[attribute] - a[attribute]
      );
    }
    this.setState({ sortedDevices, order: switchOrder ? order : stateOrder, orderBy: attribute, type });
  }

  handlePasswordDialog = (wipingID) => () => this.setState({ wipingID });

  getWipeStatus(status) {
    switch(status) {
      case 0: return 'Unknown';
      case 1: return 'OK';
      case 2: return 'Pending';
      case 4: return 'Requested';
      case 8: return 'Wiped';
      default: return 'Unknown';
    }
  }

  handleRemoteWipeConfirm = password => {
    const { wipeItOffTheFaceOfEarth, domainID, userID } = this.props;
    const { wipingID } = this.state;

    wipeItOffTheFaceOfEarth(domainID, userID, wipingID, password)
      .then(() => this.updateWipeStatus(2, wipingID))
      .catch(snackbar => this.setState({ snackbar }));
  }
  
  handleRemoteWipeCancel = deviceID => () => {
    const { panicStopWiping, domainID, userID } = this.props;
    panicStopWiping(domainID, userID, deviceID)
      .then(() => this.updateWipeStatus(1, deviceID))
      .catch(snackbar => this.setState({ snackbar }));
  }

  updateWipeStatus(status, deviceID) {
    const { sortedDevices } = this.state;
    const idx = sortedDevices.findIndex(d => d.deviceid === deviceID);
    const copy = [...sortedDevices];
    copy[idx].wipeStatus = status;
    this.setState({
      snackbar: "Success!",
      sortedDevices: copy,
      wipingID: '',
    });
    return true;
  }

  handleResync = deviceID => () => {
    const { resync, domainID, userID } = this.props;

    resync(domainID, userID, deviceID)
      .then(message => this.setState({ snackbar: 'Success! ' + (message || '') }))
      .catch(snackbar => this.setState({ snackbar }));
  }

  handleRemoteDelete = deviceID => () => {
    const { deleteDevice, domainID, userID } = this.props;

    deleteDevice(domainID, userID, deviceID)
      .then(message => this.setState({ snackbar: 'Success! ' + (message || '') }))
      .catch(snackbar => this.setState({ snackbar }));
  }

  render() {
    const { classes, t, sync } = this.props;
    const { sortedDevices, order, orderBy, wipingID, snackbar } = this.state;

    return (
      <FormControl className={classes.form}>
        <Grid container alignItems="center"  className={classes.headline}>
          <Typography variant="h6">{t('Mobile devices')}</Typography>
        </Grid>
        <Table size="small">
          <TableHead>
            <TableRow>
              {this.columns.map((column, key) =>
                <TableCell
                  key={key}
                  padding={column.padding || 'normal'}
                >
                  <TableSortLabel
                    active={orderBy === column.value}
                    align="left" 
                    direction={order}
                    onClick={this.handleSort(column.value, column.type, true)}
                  >
                    {t(column.label)}
                  </TableSortLabel>
                </TableCell>
              )}
              <TableCell padding="checkbox">{t('Actions')}</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {(sortedDevices || sync).map((obj, idx) =>
              <TableRow key={idx}>
                <TableCell>{obj.deviceid || ''}</TableCell>
                <TableCell>{obj.deviceuser || ''}</TableCell>
                <TableCell>{(obj.devicetype || '') + ' / ' + (obj.useragent || '')}</TableCell>
                <TableCell>{obj.firstsynctime ? parseUnixtime(obj.firstsynctime) : ''}</TableCell>
                <TableCell>{obj.lastupdatetime ? parseUnixtime(obj.lastupdatetime) : ''}</TableCell>
                <TableCell>{obj.asversion || ''}</TableCell>
                <TableCell>{(obj.foldersSynced || '') + '/' + (obj.foldersSyncable || '')}</TableCell>
                <TableCell>{this.getWipeStatus(obj.wipeStatus)}</TableCell>
                <TableCell style={{ display: 'flex' }}>
                  {obj.wipeStatus >= 2 && <Tooltip title="Cancel remote wipe" placement="top">
                    <IconButton onClick={this.handleRemoteWipeCancel(obj.deviceid)}>
                      <DoNotDisturbOn color="secondary"/>
                    </IconButton>
                  </Tooltip>}
                  {obj.wipeStatus < 2 && <Tooltip title="Remote wipe" placement="top">
                    <IconButton onClick={this.handlePasswordDialog(obj.deviceid)}>
                      <CleaningServices color="error" />
                    </IconButton>
                  </Tooltip>}
                  <Tooltip title="Resync" placement='top'>
                    <IconButton onClick={this.handleResync(obj.deviceid)}>
                      <SyncIcon color="primary"/>
                    </IconButton>
                  </Tooltip>
                  <Tooltip title="Delete device" placement='top'>
                    <IconButton onClick={this.handleRemoteDelete(obj.deviceid)}>
                      <Delete color="error"/>
                    </IconButton>
                  </Tooltip>
                </TableCell>
              </TableRow>
            )}
          </TableBody>
        </Table>
        <PasswordSafetyDialog
          open={Boolean(wipingID)}
          deviceID={wipingID}
          onClose={this.handlePasswordDialog('')}
          onConfirm={this.handleRemoteWipeConfirm}
        />
        <Feedback
          snackbar={snackbar || ''}
          onClose={() => this.setState({ snackbar: '' })}
        />
      </FormControl>
    );
  }
}

Sync.propTypes = {
  classes: PropTypes.object.isRequired,
  t: PropTypes.func.isRequired,
  fetch: PropTypes.func.isRequired,
  sync: PropTypes.array.isRequired,
  domainID: PropTypes.number,
  userID: PropTypes.number,
  wipeItOffTheFaceOfEarth: PropTypes.func.isRequired,
  resync: PropTypes.func.isRequired,
  deleteDevice: PropTypes.func.isRequired,
  panicStopWiping: PropTypes.func.isRequired,
};

const mapStateToProps = state => {
  return {
    sync: state.users.Sync || [],
  };
};

const mapDispatchToProps = dispatch => {
  return {
    fetch: async (domainID, userID) => await dispatch(fetchUserSync(domainID, userID))
      .catch(err => console.error(err)),
    wipeItOffTheFaceOfEarth: async (domainID, userID, deviceID, password) =>
      await dispatch(engageRemoteWipe(domainID, userID, deviceID, password))
        .catch(err => Promise.reject(err)),
    resync: async (domainID, userID, deviceID) =>
      await dispatch(engageResync(domainID, userID, deviceID))
        .then(resp => resp)
        .catch(err => Promise.reject(err)),
    deleteDevice: async (domainID, userID, deviceID) =>
      await dispatch(engageRemoteDelete(domainID, userID, deviceID))
        .then(resp => resp)
        .catch(err => Promise.reject(err)),
    panicStopWiping: async (domainID, userID, deviceID) =>
      await dispatch(cancelRemoteWipe(domainID, userID, deviceID))
        .then(resp => resp)
        .catch(err => Promise.reject(err)),
  };
};

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