import {
  Checkbox,
  Grid,
  LinearProgress,
  Table,
  TableBody,
  TableCell,
  TableFooter,
  TablePagination,
  TableRow,
  Tooltip,
} from "@material-ui/core";
import AddCircleIcon from "@material-ui/icons/AddCircle";
import clsx from "clsx";
import React, { useEffect, useState, useRef } from "react";
import { Link } from "react-router-dom";

import { logger } from "../../../../../services/monitoring";
import {
  FleetProvider,
  useFleetContext
} from "../../../../Contexts/FleetContext";
import { useStatusContext } from "../../../../Contexts/StatusContext";
import { useUserContext } from "../../../../Contexts/UserContext";
import SearchField from "../../../../Controls/SearchField";
import TableHeaderSortable from "../../../../Table/HeaderSortable";
import { useLocalStorage } from "../../../../useLocalStorage";
import BulkActions from "../../../../BulkActions";
import Battery from "../../../../Battery";
import { VehicleTeaserController as VehicleTeaser } from "../../../../VehicleTeaser";
import useStyles from "../../../../useStyles";

const tableColumns = [
  {
    id: "vehicle",
    label: "Vehicle",
  },
  {
    id: "trex_version",
    label: "T.REX Version",
  },
  {
    id: "car_update",
    label: "Car Update",
  },
  {
    id: "car_update_status",
    label: "Car Update Status",
  },
  {
    id: "battery",
    label: "Battery",
  },
  {
    id: "voltage",
    label: "Voltage",
  },
  {
    id: "park", // TODO: Update to 'gear' when we confirm each possible state
    label: "Park",
  },
];

const PAGE_SIZE = "FLEET_STATUS_VEHICLES_TABLE_PAGE_SIZE";

const MainForm = ({ name }) => {
  const [pageSize, setPageSize] = useLocalStorage(PAGE_SIZE, 10);
  const [pageIndex, setPageIndex] = useState(0);
  const [orderBy, setOrderBy] = useState("id");
  const [order, setOrder] = useState("desc");
  const [search, setSearch] = useState("");
  const [selected, setSelected] = useState([]);
  const [selectAll, setSelectAll] = useState(false);
  const [fleetVINs, setFleetVINs] = useState([]);
  const componentMounted = useRef(true);
  const classes = useStyles();
  const { setMessage } = useStatusContext();
  const {
    fleetVehicles,
    totalFleetVehicles,
    watchFleetVehicles,
    getFleetVehicles,
    getFleetVINs,
    removeFleetVehiclesLocal,
  } = useFleetContext();
  const {
    token: {
      idToken: { jwtToken: token },
    },
  } = useUserContext();

  const handleSearch = (query) => {
    setSearch(query);
  };

  useEffect(() => {
    (async () => {
      try {
        if (!name || !token) return;
        await getFleetVehicles(
          name,
          {
            search,
            limit: pageSize,
            offset: pageSize * pageIndex,
            order: `${orderBy} ${order}`,
          },
          token
        );
        await getFleetVINs(
          name,
          token
        ).then((vins) => {
          setFleetVINs(vins);
        });
        if (componentMounted.current) {
          watchFleetVehicles.start({ token });
        }
      } catch (e) {
        setMessage(e.message);
        logger.warn(e.stack);
        watchFleetVehicles.end();
      }
    })();
    return () => {
      componentMounted.current = false;
      watchFleetVehicles.end();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [token, pageIndex, pageSize, orderBy, order, search]);

  const handleChangePageIndex = (event, newIndex) => {
    setPageIndex(newIndex);
  };

  const handleChangePageSize = (event) => {
    setPageSize(parseInt(event.target.value, 10));
    setPageIndex(0);
  };

  const handleSort = (event, property) => {
    try {
      if (property === orderBy) {
        if (order === "asc") {
          setOrder("desc");
        } else {
          setOrder("asc");
        }
      } else {
        setOrderBy(property);
        setOrder("asc");
      }
    } catch (e) {
      logger.warn(e.stack);
    }
  };

  const handleSelectAll = () => {
    setSelectAll(!selectAll);
    setSelected(!selectAll ? fleetVINs : []);
  };

  const handleSelect = (vin, setState) => {
    setSelected(selected => setState
      ? [...selected, vin]
      : selected.filter(select => select !== vin));
  };

  const bulkActionCallback = (action, _, context) => {
    if (action === "updateFleetVehicles") {
      const vinsToRemove = context.fromFleet === name ? context.fromVehicles : [];
      removeFleetVehiclesLocal(vinsToRemove);
    }
  }

  return (
    <div className={clsx(classes.paper, classes.tableSize)}>
      <Grid container className={classes.root} spacing={2}>
        <Grid item md={1} className={classes.textJustifyAlign}>
          <Link to={`/fleet/${name}/vehicle-add`}>
            <AddCircleIcon fontSize="large" />
          </Link>
        </Grid>
        <Grid item md={4}>
          <BulkActions
            actions={["updateFleetVehicles", "addTags", "sms", "updateConfig", "remoteCommand", "diagnostic", "updateFlashpackNumbers"]}
            ids={selected}
            callback={bulkActionCallback}
          />
        </Grid>
        <Grid item md={5} align="right" className={classes.textCenterAlign}>
          <SearchField classes={classes} onSearch={handleSearch} />
        </Grid>
      </Grid>
      <Table>
        <TableHeaderSortable
          classes={classes}
          orderBy={orderBy}
          order={order}
          columnData={tableColumns}
          onSortRequest={handleSort}
          multiSelect={true}
          onSelectAll={handleSelectAll}
          selectCount={selected ? selected.length : 0}
          rowCount={fleetVehicles.length}
          selectAllForAllPages={true}
        />
        <TableBody>
          {fleetVehicles && fleetVehicles.map((car) => {
            const isSelected = selected.includes(car.vin);
            return (car.vin && <TableRow key={"row" + car.vin}>
              <TableCell padding="checkbox">
                <Checkbox
                  checked={isSelected}
                  onChange={() => handleSelect(car.vin, !isSelected)}
                />
              </TableCell>
              <TableCell key={"cell" + car.vin} align="center">
                <VehicleTeaser
                  vin={car.vin}
                  icc={car.connectedHMI}
                  trex={car.connected}
                  token={token}
                />
              </TableCell>
              <TableCell key={"cell2" + car.vin} align="center">{car.trex_version}</TableCell>
              <TableCell key={"cell3" + car.car_update_name}>
                <Tooltip key={"cell3tooltip"} title={`${car.car_update_id} / ${car.car_update_type}`}>
                  <Link to={`/vehicle-status/${car.vin}/${car.car_update_id}`} className={classes.truncateCell}>
                    {car.car_update_name}
                  </Link>
                </Tooltip>
              </TableCell>
              <TableCell key={"cell4" + car.vin}>
                {car.car_update_status}
                {car.car_update_progress > -1 && (
                  <LinearProgress variant="determinate" value={car.car_update_progress} />
                )}
              </TableCell>
              <TableCell key={"cell5" + car.vin} align="left">
                <Battery percent={car.charge} charge={car.charge_type} />
              </TableCell>
              <TableCell key={"cell6" + car.vin}>
                {car.voltage > 0 && `${car.voltage}V`}
              </TableCell>
              <TableCell key={"cell7" + car.vin}>
                {car.park ? "Yes" : "No"}
              </TableCell>
            </TableRow>
            )
          })}
        </TableBody>
        <TableFooter>
          <TableRow>
            <TablePagination
              rowsPerPageOptions={[5, 10, 25, 100]}
              colSpan={8}
              count={totalFleetVehicles}
              rowsPerPage={pageSize}
              page={pageIndex}
              SelectProps={{
                inputProps: { "aria-label": "rows per page" },
                native: true,
              }}
              onPageChange={handleChangePageIndex}
              onRowsPerPageChange={handleChangePageSize}
            />
          </TableRow>
        </TableFooter>
      </Table>
    </div>
  );
};

const FleetVehiclesTable = (props) => (
  <FleetProvider>
    <MainForm {...props} />
  </FleetProvider>
);

export default FleetVehiclesTable;
