import {
  Avatar,
  Box,
  Card,
  CardActionArea,
  CardContent,
  CardHeader,
  //Grid2 as Grid,
  Switch,
  Theme,
  Tooltip,
  Typography
} from "@mui/material";
import Grid from '@mui/material/Grid2';
import EventBlocker from "common/EventBlocker";
import PendingChangesIndicator from "common/PendingChangesIndicator";
import MeasurementSummary from "component/MeasurementSummary";
import { useComponentAPI, usePendingChanges, useSnackbar, useThemeType } from "hooks";
import InteractionsOverview from "interactions/InteractionsOverview";
import { cloneDeep } from "lodash";
import { Component, Device, Interaction } from "models";
import moment from "moment";
import { getFriendlyAddressTypeName, getHumanReadableAddress } from "pbHelpers/AddressType";
import { controllerModeLabel } from "pbHelpers/Component";
import {
  //extension,
  GetComponentIcon,
  getMeasurements,
  isController
} from "pbHelpers/ComponentType";
import { DeviceAvailabilityMap, OffsetAvailabilityMap } from "pbHelpers/DeviceAvailability";
import { findInteractionsAsSource, HasInteraction } from "pbHelpers/Interaction";
import { canWrite } from "pbHelpers/Permission";
import { pond, quack } from "protobuf-ts/pond";
import React, { useEffect, useState } from "react";
// import { useHistory } from "react-router";
import { hasDeviceFeature } from "services/feature/service";
import ComponentActions from "./ComponentActions";
import { or } from "utils";
import { extractNodes } from "pbHelpers/ComponentTypes";
import UnitMeasurementSummary from "./UnitMeasurementSummary";
import { UnitMeasurement } from "models/UnitMeasurement";
import { useGlobalState } from "providers";
import { makeStyles } from "@mui/styles";
import { useLocation, useNavigate } from "react-router-dom";

const useStyles = makeStyles((theme: Theme) => {
  return ({
    card: {
      position: "relative",
      display: "flex",
      height: "100%",
      flexDirection: "column",
      overflow: "visible"
    },
    cardHeader: {
      padding: theme.spacing(1),
      paddingLeft: theme.spacing(2)
    },
    cardContent: {
      display: "flex",
      flexDirection: "column",
      justifyContent: "space-between",
      alignItems: "center",
      padding: theme.spacing(1),
      paddingTop: 0
    },
    moreDetails: {
      marginLeft: "auto"
    },
    avatarIcon: {
      width: theme.spacing(3),
      height: theme.spacing(3)
    },
    sensorDot: {
      position: "absolute",
      marginLeft: theme.spacing(1),
      marginTop: theme.spacing(1)
    }
  })
});

interface Sensor {
  label: string;
  color: string;
  value: string;
}

interface Props {
  device: Device;
  component: Component;
  components: Component[];
  availablePositions: DeviceAvailabilityMap;
  availableOffsets: OffsetAvailabilityMap;
  permissions: pond.Permission[];
  interactions: Interaction[];
  refreshCallback: (updatedComponent?: Component) => void;
  showMobile?: boolean;
  showSensors?: boolean;
  deviceComponentPreferences?: pond.DeviceComponentPreferences;
}

export default function ComponentCard(props: Props) {
  const componentAPI = useComponentAPI();
  const classes = useStyles();
  const themeType = useThemeType();
  const { error, success } = useSnackbar();
  const {
    device,
    component,
    components,
    availablePositions,
    availableOffsets,
    permissions,
    refreshCallback,
    interactions,
    showMobile,
    showSensors,
    deviceComponentPreferences
  } = props;
  // const history = useHistory();
  const navigate = useNavigate()
  const location = useLocation()
  const [sensors, setSensors] = useState<Sensor[]>([]);
  const [{ user, showErrors, as }] = useGlobalState();
  const { pending: pendingChanges, accepted: changesAccepted } = usePendingChanges(
    component.status.synced
  );

  const updateControllerState = (checked: boolean) => {
    let updatedComponent = cloneDeep(component);
    let newMode =
      checked === false ? 2 : HasInteraction(component.location(), interactions) ? 0 : 1;
    updatedComponent.settings.defaultOutputState = newMode;
    let describe = controllerModeLabel(newMode);

    componentAPI
      .update(device.id(), updatedComponent.settings, undefined, undefined, as)
      .then(() => {
        success(component.name() + "'s mode was set to " + describe);
        updatedComponent.status.synced = false;
        updatedComponent.status.lastUpdate = moment().toISOString();
        refreshCallback(updatedComponent);
      })
      .catch(() => {
        error("Failed to set " + component.name() + "'s mode");
      });
  };

  const pathToComponent = () => {
    let url = location.pathname + "/components/" + component.key();
    url = url.replace("//", "/");
    return url;
  };

  const openComponentPage = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    const { name, className } = event.target as HTMLButtonElement;
    const blacklist = ["slider", "controllerSwitch"];
    if (
      blacklist.includes(name) ||
      blacklist.find(
        v =>
          className &&
          className
            .toString()
            .toLowerCase()
            .includes(v)
      ) !== undefined
    ) {
      event.preventDefault();
    } else {
      navigate(pathToComponent());
    }
  };

  const getAddressDescription = () => {
    if (
      component.settings.addressType === quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY ||
      (component.settings.addressType >= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET1 &&
        component.settings.addressType <= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET100)
    ) {
      let addressDescription = getHumanReadableAddress(
        component.settings.addressType,
        component.settings.type,
        component.settings.address,
        device.settings.product
      );
      if (addressDescription === "") {
        addressDescription = "Internal";
      }
      let port = "Port: " + addressDescription;
      let cableID = "";
      if (
        component.settings.addressType >= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET1 &&
        component.settings.addressType <= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET100
      ) {
        cableID = "Cable: " + (component.settings.addressType - 8);
      }
      return port + " " + cableID;
    } else if (component.settings.addressType === quack.AddressType.ADDRESS_TYPE_I2C) {
      let description = ""
      let type = getFriendlyAddressTypeName(component.settings.addressType);
      description = type
      if(component.settings.expansionLine){
        description = description + ": Exp Line " + component.settings.expansionLine
      }
      if(component.settings.muxLine){
        description = description + " ,Mux Line " + component.settings.muxLine
      }
      return description
    }else{
      return getFriendlyAddressTypeName(component.settings.addressType);
    }
  };

  const header = () => {
    const canEdit = canWrite(permissions);
    const componentIcon = GetComponentIcon(
      component.settings.type,
      component.settings.subtype,
      themeType
    );
    const name = component.name();

    let measurements: UnitMeasurement[] = [];
    if (component.status.lastGoodMeasurement)
      measurements = component.status.lastGoodMeasurement.map(um => UnitMeasurement.any(um, user));

    if (showErrors)
      measurements = component.lastMeasurement.map(um => UnitMeasurement.any(um, user));

    return (
      <CardHeader
        avatar={
          componentIcon ? (
            <Avatar
              variant="square"
              src={componentIcon}
              className={classes.avatarIcon}
              alt={name}
            />
          ) : (
            <Box className={classes.avatarIcon} />
          )
        }
        title={
          <React.Fragment>
            <Tooltip
              title={
                <div>
                  Subtype: {component.subTypeName()}
                  <br />
                  ID: {component.key()}
                  <br />
                  Location: {component.locationString()}
                </div>
              }
              placement="top">
              <span>
                {name} - <Typography variant="caption">{getAddressDescription()}</Typography>
              </span>
            </Tooltip>
            {isController(component.settings.type) &&
              hasDeviceFeature(device.settings.upgradeChannel, "better-controls") && (
                <Box component="span" paddingLeft={1}>
                  <Switch
                    checked={
                      component.settings.defaultOutputState === 0 ||
                      component.settings.defaultOutputState === 1
                    }
                    color="default"
                    size="small"
                    onTouchStart={event => {
                      event.stopPropagation();
                      //event.preventDefault();
                    }}
                    onMouseDown={event => {
                      event.stopPropagation();
                      //event.preventDefault();
                    }}
                    onClick={event => {
                      event.stopPropagation();
                      //event.preventDefault();
                    }}
                    disabled={!canEdit}
                    onChange={(_, checked) => updateControllerState(checked)}
                    name="controllerSwitch"
                    inputProps={{ "aria-label": "controller switch" }}
                  />
                </Box>
              )}
          </React.Fragment>
        }
        className={classes.cardHeader}
        titleTypographyProps={{ variant: "subtitle1" }}
        subheader={
          <React.Fragment>
            {(pendingChanges || changesAccepted) && (
              <Typography variant="caption" color="textSecondary" component="div">
                <PendingChangesIndicator
                  pending={pendingChanges}
                  accepted={changesAccepted}
                  text={
                    changesAccepted
                      ? "Pending change accepted"
                      : "Pending " + moment(component.status.lastUpdate).fromNow()
                  }
                />
              </Typography>
            )}
            {/* !newStructure ? (
              <MeasurementSummary
                component={component}
                reading={component.status.lastMeasurement}
                dense
              />
            ) : ( */}
            <UnitMeasurementSummary
              component={component}
              reading={UnitMeasurement.convertLastMeasurement(measurements)}
              //dense
            />
            {/* ) */}
          </React.Fragment>
        }
        action={
          <EventBlocker>
            <ComponentActions
              device={device}
              component={component}
              components={components}
              availablePositions={availablePositions}
              availableOffsets={availableOffsets}
              refreshCallback={refreshCallback}
              permissions={permissions}
              deviceComponentPreferences={deviceComponentPreferences}
            />
          </EventBlocker>
        }
      />
    );
  };

  const content = () => {
    if (findInteractionsAsSource(component.location(), interactions).length <= 0) return null;
    return (
      <CardContent className={classes.cardContent}>
        <EventBlocker>
          <InteractionsOverview
            device={device}
            component={component}
            components={components}
            interactions={interactions}
            permissions={permissions}
            refreshCallback={() => refreshCallback()}
          />
        </EventBlocker>
      </CardContent>
    );
  };

  useEffect(() => {
    if (!component) return;
    if (!component.status) return;
    if (!component.status.lastMeasurement) return;
    let measurements = getMeasurements(component.type(), or(component.settings.subtype, 0));
    let nodes = extractNodes(component.status!.lastMeasurement!.measurement!);
    let sensors: Sensor[] = [];
    nodes.forEach(node => {
      Object.values(node).forEach((value, index) => {
        if (measurements[index]) {
          let sensor: Sensor = {
            label: measurements[index].label,
            value: value,
            color: measurements[index].colour
          };
          sensors.push(sensor);
        }
      });
    });
    setSensors(sensors);
  }, [component, setSensors]);

  const sensorCard = () => {
    if (sensors.length <= 0 || !showSensors) return null;
    return (
      <CardContent className={classes.cardContent}>
        <EventBlocker>
          {sensors.map((sensor, index) => {
            return (
              <Typography variant="body2" key={index}>
                {sensor.label}: {sensor.value}
              </Typography>
            );
          })}
        </EventBlocker>
      </CardContent>
    );
  };

  return (
      <Card raised className={classes.card}>
        <CardActionArea
          onClick={(event: any) => openComponentPage(event)}
          component="div"
          style={{ height: "100%" }}>
          {header()}
          {content()}
          {sensorCard()}
        </CardActionArea>
      </Card>

  );
}
