import { useComponentAPI, useMineAPI, useThemeType } from "hooks";
import React, { useEffect, useState } from "react";
import { Component } from "models";
import {
  Avatar,
  Box,
  Card,
  CardContent,
  CardHeader,
  Checkbox,
  CircularProgress,
  Grid2 as Grid,
  Theme,
  Typography,
  useTheme
} from "@mui/material";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
import { pond } from "protobuf-ts/pond";
import { GetComponentIcon } from "pbHelpers/ComponentType";
import EventBlocker from "common/EventBlocker";
import UnitMeasurementSummary from "component/UnitMeasurementSummary";
import { UnitMeasurement } from "models/UnitMeasurement";
import { useGlobalState } from "providers";
import DelayedTextField from "common/DelayedTextInput";
import { makeStyles } from "@mui/styles";
import { useNavigate } from "react-router-dom";

interface Props {
  deviceId: number;
  showMobile?: boolean;
  mineComponents: Component[];
  setMineComponents: React.Dispatch<React.SetStateAction<Component[]>>;
  mineComponentPreferences: Map<string, pond.MineComponentPreferences>;
  setMineComponentPreferences: React.Dispatch<
    React.SetStateAction<Map<string, pond.MineComponentPreferences>>
  >;
  keys?: string[];
  types?: string[];
}

const useStyles = makeStyles((theme: Theme) => {
  return ({
    avatarIcon: {
      width: theme.spacing(3),
      height: theme.spacing(3)
    },
    card: {
      position: "relative",
      display: "flex",
      flexDirection: "column",
      overflow: "visible",
      width: "100%"
    },
    cardContent: {
      display: "flex",
      flexDirection: "column",
      justifyContent: "space-between",
      alignItems: "center",
      padding: theme.spacing(1),
      paddingTop: 0
    },
    onHover: {
      "&:hover": {
        textDecoration: "underline",
        cursor: "pointer"
      }
    }
  })
});

export default function ComponentCards(props: Props) {
  const {
    deviceId,
    showMobile,
    setMineComponents,
    mineComponents,
    mineComponentPreferences,
    setMineComponentPreferences
  } = props;
  const componentAPI = useComponentAPI();
  const mineAPI = useMineAPI();
  const [cards, setCards] = useState<JSX.Element[]>([]);
  const [loading, setLoading] = useState(false);
  const [firstLoad, setFirstLoad] = useState(true);
  const themeType = useThemeType();
  const classes = useStyles();
  const [{ user, as }] = useGlobalState();
  const theme = useTheme();
  const navigate = useNavigate()

  const keys = props.keys ? props.keys : getContextKeys();
  const types = props.types ? props.types : getContextTypes();

  const removeComponent = (device: string, component: Component) => {
    let mine = "";
    types.forEach((type, index) => {
      if (type === "mine") mine = keys[index];
    });
    mineAPI.addComponent(mine, device, component.key(), [pond.Permission.PERMISSION_INVALID], as);
  };

  const addComponent = (device: string, component: Component) => {
    let mine = "";
    types.forEach((type, index) => {
      if (type === "mine") mine = keys[index];
    });
    mineAPI
      .addComponent(mine, deviceId.toString(), component.key(), [
        pond.Permission.PERMISSION_READ,
        pond.Permission.PERMISSION_SHARE,
        pond.Permission.PERMISSION_WRITE,
        pond.Permission.PERMISSION_USERS
      ], as)
      .then(() => {
        let prefs = getPreferences(component);
        mineComponentPreferences.set(component.key(), prefs);
        setMineComponentPreferences(new Map(mineComponentPreferences));
        let c = mineComponents;
        c.push(component);
        setMineComponents([...c]);
      });
  };

  const getPreferences = (component: Component) => {
    let exists = mineComponents.find(comp => comp.key() === component.key());
    let prefs = mineComponentPreferences.get(component.key());
    if ((!prefs?.sensors || prefs.sensors.length < 1) && exists) {
      prefs = pond.MineComponentPreferences.create();
      prefs.sensors = [];
      if (component.lastMeasurement.length > 0) {
        if (component.lastMeasurement[0].values)
          component.lastMeasurement[0].values[0].values.forEach((v, i) => {
            let sensor = pond.MineSensorPreferences.create();
            sensor.enabled = false;
            sensor.x = 20;
            sensor.y = 20;
            sensor.nickname = component.name();
            if (component.lastMeasurement[0].values[0].values.length > 1) {
              sensor.nickname = "Sensor " + i;
            }
            prefs!.sensors.push(sensor);
          });
        mineComponentPreferences.set(component.key(), prefs);
        setMineComponentPreferences(new Map(mineComponentPreferences));
      }
    }
    return prefs!;
  };

  useEffect(() => {
    let k = [...keys];
    k.push(deviceId.toString());
    let t = [...types];
    t.push("device");
    setLoading(true);
    componentAPI
      .list(deviceId, false, k, t, true, as)
      .then(resp => {
        if (loading) return;
        if (!resp.data.components) return;
        setLoading(true);
        let components: Component[] = [];
        let cards: JSX.Element[] = [];

        resp.data.components.forEach((comp, index) => {
          if (!comp) return;
          let component = Component.create(comp);

          // Ignore component without data
          if (!component.lastMeasurement) return;
          let measurement: UnitMeasurement[] = [];
          if (component.lastMeasurement.forEach) {
            component.lastMeasurement.forEach(m => {
              measurement.push(UnitMeasurement.any(m, user));
            });
          }
          components.push(component);
          const exists = mineComponents.find(comp => comp.key() === component.key());
          const componentIcon = GetComponentIcon(component.type(), component.subType(), themeType);
          let prefs = getPreferences(component);
          cards.push(
            <div key={cards.length + 1} style={{ padding: 6 }}>
              <Card raised className={classes.card}>
                <CardHeader
                  avatar={
                    componentIcon ? (
                      <Avatar
                        variant="square"
                        src={componentIcon}
                        className={classes.avatarIcon}
                        alt={component.name()}
                      />
                    ) : (
                      <Box className={classes.avatarIcon} />
                    )
                  }
                  title={
                    component.name() ? (
                      <Typography
                        className={classes.onHover}
                        onClick={() => {
                          navigate(
                            window.location.pathname +
                              "/devices/" +
                              deviceId +
                              "/components/" +
                              component.key()
                          , { replace: true });
                        }}>
                        {component.name()}
                      </Typography>
                    ) : (
                      "No Name"
                    )
                  }
                  subheader={
                    <UnitMeasurementSummary
                      component={component}
                      reading={UnitMeasurement.convertLastMeasurement(measurement)}
                      dense
                    />
                  }
                  action={
                    <EventBlocker>
                      <Checkbox
                        checked={!!exists}
                        disabled={loading}
                        onChange={() => {
                          if (!exists) {
                            addComponent(deviceId.toString(), component);
                          } else {
                            removeComponent(deviceId.toString(), component);
                          }
                        }}
                      />
                    </EventBlocker>
                  }
                />
                {exists && (
                  <CardContent className={classes.cardContent}>
                    <EventBlocker>
                      {prefs?.sensors.map((sensor, i) => {
                        let reading = UnitMeasurement.convertLastMeasurementByNode(measurement, i);
                        return (
                          <Grid
                            container
                            spacing={2}
                            key={"grid-" + i}
                            direction="row"
                            style={{
                              boxShadow: "inset 0px 0px 12px rgba(0,0,0,0.5)",
                              marginTop: i > 0 ? 10 : 0
                            }}>
                            <Grid size={{ xs: 10 }}>
                              <Grid container direction="column">
                                <DelayedTextField
                                  value={sensor.nickname}
                                  variant="outlined"
                                  title="Nickname"
                                  onChange={e => {
                                    let prefs = mineComponentPreferences.get(component.key());
                                    if (prefs) {
                                      prefs.sensors[i].nickname = e.toString();
                                      mineComponentPreferences.set(component.key(), prefs);
                                      setMineComponentPreferences(
                                        new Map(mineComponentPreferences)
                                      );
                                    }
                                  }}
                                  delayMS={2000}
                                  size="small"
                                  inputProps={{
                                    style: { fontSize: 12 }
                                  }}
                                  disabled={loading}
                                />
                              </Grid>
                              <Grid container spacing={1}>
                                <Grid style={{ marginLeft: 6 }}>
                                  <UnitMeasurementSummary
                                    component={component}
                                    reading={reading}
                                    dense
                                  />
                                </Grid>
                                <Grid >
                                  <Typography variant={"caption"} style={{ fontSize: 12 }}>
                                    {"(" + sensor.x + ", " + sensor.y + ")"}
                                  </Typography>
                                </Grid>
                              </Grid>
                            </Grid>
                            <Grid size={{ xs: 2 }}>
                              <Box
                                display="flex"
                                justifyContent={"center"}
                                alignItems={"center"}
                                minHeight="100%"
                                maxHeight="100%">
                                <Checkbox
                                  checked={sensor.enabled}
                                  size="small"
                                  onChange={() => {
                                    let prefs = mineComponentPreferences.get(component.key());
                                    if (sensor.enabled) {
                                      if (prefs) {
                                        prefs.sensors[i].enabled = false;
                                        sensor.enabled = false;
                                        mineComponentPreferences.set(component.key(), prefs);
                                        setMineComponentPreferences(
                                          new Map(mineComponentPreferences)
                                        );
                                      }
                                    } else {
                                      if (prefs) {
                                        sensor.enabled = true;
                                        mineComponentPreferences.set(component.key(), prefs);
                                        setMineComponentPreferences(
                                          new Map(mineComponentPreferences)
                                        );
                                      }
                                    }
                                  }}
                                />
                              </Box>
                            </Grid>
                          </Grid>
                        );
                      })}
                    </EventBlocker>
                  </CardContent>
                )}
              </Card>
            </div>
          );
        });
        setCards(cards);
        //setComponents(components);
      })
      .finally(() => {
        setFirstLoad(false);
        setLoading(false);
      });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [deviceId, componentAPI, showMobile, keys, types, as]);

  return (
    <Grid container direction="row" justifyContent="flex-start" spacing={2}>
      {firstLoad ? (
        <div
          style={{
            margin: theme.spacing(2),
            marginLeft: "auto",
            marginRight: "auto"
          }}>
          <CircularProgress />
        </div>
      ) : (
        cards
      )}
    </Grid>
  );
}
