import clsx from "clsx";

import { Button, FormControl, InputLabel, Select, Grid, Switch } from "@material-ui/core";
import React, { useEffect, useState } from "react";
import { useStatusContext } from "../../Contexts/StatusContext";
import { logger } from "../../../services/monitoring";
import smsAPI from "../../../services/smsAPI";
import cmp from "semver-compare";
import PropTypes from 'prop-types';


import {
  useVehicleContext
} from "../../Contexts/VehicleContext";

const DIAGNOSTIC_COMMANDS = [
  { displayname: "Reset", val: "remote_reset" },
  { displayname: "Set CAN Network State", val: "can_network" },
  { displayname: "Set Remote Ignition", val: "remote_ignition" },
  { displayname: "Send Wake Up SMS", val: "sms" },
  // { displayname: "Update SecOC keys", val: "write_secoc_key" },
  { displayname: "Read ECU versions", val: "read_ecu_versions" },
]

const SendDiagnosticCommand = ({ vin, token, classes }) => {

  const { vehicle, getVehicle, getState, sendDiagnosticCommand, getECUs } = useVehicleContext();

  const [carState, setCarState] = useState(null);
  const [ecus, setEcus] = useState([]);
  const { setMessage } = useStatusContext();

  const [currentCommand, setCurrentCommand] = useState(DIAGNOSTIC_COMMANDS[0].val);
  const [currentECU, setCurrentECU] = useState("");
  const [canNetState, setCanNetState] = useState(false);
  const [ignitionState, setIgnitionState] = useState(false);
  const [seconds, setSeconds] = useState(180);

  const changeCommandHandler = (e) => {
    setCurrentCommand(e.target.value);
  };


  //Update online/offline state
  useEffect(() => {
    if (!vin) return;
    getCarState();
    const interval = setInterval(getCarState, 5000);
    return () => { clearInterval(interval); }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [vin]);

  //Get ECUs
  useEffect(() => {
    (async () => {
      if (!vin) return;
      const unique = true;
      const result = await getECUs({ vin, unique }, token)
      sortECUs(result.data)
      result.data.push({ ecu: "TBOX" })
      setCurrentECU(result.data[0].ecu)
      setEcus(result.data)
      await getVehicle(vin, token);
    })();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [vin]);

  const getCarState = async () => {
    try {
      const result = await getState(token, vin);
      setCarState(result.data);
    } catch (e) {
      setMessage(e.message);
      logger.warn(e.stack);
    }
  };

  const isOnline = () => {
    return carState && carState?.online;
  };
  const sortECUs = (ecus) => {
    return ecus.sort((a, b) => { return a.ecu < b.ecu ? -1 : a.ecu > b.ecu ? 1 : 0 })
  }

  const TREX_MIN_VER = "1.1.141";
  const isRemoteResetSupported = () => {
    return !carState?.trex_version ? true
      : cmp(carState.trex_version, TREX_MIN_VER) >= 0
      || carState.trex_version.includes("dev")
      || carState.trex_version.includes("0.0.0");
  };

  const clickHandler = async (_) => {
    try {
      if (currentCommand === "remote_reset") {
        await sendDiagnosticCommand([vin], { command: currentCommand, ecu_name: currentECU }, token);
      }
      else if (currentCommand === "can_network") {
        await sendDiagnosticCommand([vin], { command: currentCommand, can_net_action: canNetState ? "on" : "off", timeout: seconds }, token);
      } else if (currentCommand === "remote_ignition") {
        await sendDiagnosticCommand([vin], { command: currentCommand, ignition_action: ignitionState ? "on" : "off", timeout: seconds }, token);
      } else if (currentCommand === "sms") {
        const res = await smsAPI.send({ ICCID: vehicle.iccid, await: true, messageText: "remote_diagnostic" }, token)
        if (res.error) {
          setMessage(`Failed to wake up the car: ${res.error}`)
          return;
        }
      } else if (currentCommand === "read_ecu_versions") {
        await sendDiagnosticCommand([vin], { command: currentCommand, ecu_name: currentECU }, token);
      } else if (currentCommand === "write_secoc_key") {
        await sendDiagnosticCommand([vin], { command: currentCommand }, token);
      }
      setMessage(`Sent diagnostic command to ${vin}`);
    } catch (error) {
      setMessage(error.message);
      logger.error(error.stack);
    }
  };

  return (
    <div className={clsx(classes.paper, classes.tableSize)}>
      {
        currentCommand === "remote_reset"
          ?
          <AllECUsCommand classes={classes} ecus={ecus} currentECU={currentECU} setCurrentECU={setCurrentECU} />
          : currentCommand === "can_network"
            ?
            <CanNetCommand canNetState={canNetState} setCanNetState={setCanNetState} seconds={seconds} setSeconds={setSeconds} />
            : currentCommand === "remote_ignition"
              ?
              <RemoteIgnitionCommand ignitionState={ignitionState} setIgnitionState={setIgnitionState} seconds={seconds} setSeconds={setSeconds} />
              : currentCommand === "read_ecu_versions"
                ?
                <AllECUsCommand classes={classes} ecus={ecus.concat({ ecu: "*" })} currentECU={currentECU} setCurrentECU={setCurrentECU} />
                : null
      }

      <p></p>

      <FormControl
        className={classes.formControl}
        variant="outlined"
        size="small"
      >
        <InputLabel htmlFor="send-command" className={classes.whiteBackground}>
          Diagnostic Command
        </InputLabel>
        <Select
          native
          variant="outlined"
          inputProps={{
            name: "send-command",
            id: "send-command",
          }}
          onChange={changeCommandHandler}
        >
          {DIAGNOSTIC_COMMANDS.map((command, index) => (
            <option key={index} value={command.val}>
              {command.displayname}
            </option>
          ))}
        </Select>
      </FormControl>

      <Button
        type="submit"
        aria-label="send command"
        fullWidth
        variant="contained"
        color="primary"
        className={classes.submit}
        onClick={clickHandler}
        disabled={(!isOnline() || !isRemoteResetSupported()) && currentCommand !== "sms"}
      >
        Send
      </Button>
      <div>
        <b>
          {isOnline() ? "ONLINE" : "OFFLINE"}
        </b>
      </div>
      <div>
        <b>
          {!isRemoteResetSupported() ? `Remote Reset supported from ${TREX_MIN_VER}, current version ${carState.trex_version}` : ""}
        </b>
      </div>

    </div >
  );
};

export const AllECUsCommand = ({ classes, ecus, currentECU, setCurrentECU }) => {
  return (
    <FormControl
      className={classes.formControl}
      variant="outlined"
      size="small"
      margin="normal"
    >
      <InputLabel className={classes.whiteBackground}>
        ECU
      </InputLabel>
      <Select
        native
        variant="outlined"
        value={currentECU}
        onChange={(event) => {
          setCurrentECU(event.target.value)
        }}
      >
        {ecus.map((row, index) => (
          <option key={index} value={row.ecu}>
            {row.ecu}
          </option>
        ))}
      </Select>
    </FormControl>
  )
}
AllECUsCommand.propTypes = {
  classes: PropTypes.object.isRequired,
  ecus: PropTypes.array.isRequired,
  currentECU: PropTypes.string.isRequired,
  setCurrentECU: PropTypes.func.isRequired,
};

const CanNetCommand = ({ canNetState, setCanNetState, seconds, setSeconds }) => {
  return (
    <div>
      <Grid component="label" container alignItems="center" spacing={1}>
        <Grid item>Off</Grid>
        <Grid item>
          <Switch checked={canNetState} onChange={(event) => {
            setCanNetState(event.target.checked)
          }} />
        </Grid>
        <Grid item>On</Grid>
      </Grid>
      {
        canNetState ?
          <label>
            Enter amount of seconds:
            <input
              type="number"
              value={seconds}
              min={0} // Minimum value
              step={10} // Increment/decrement step
              onChange={(event) => {
                const value = event.target.value;
                setSeconds(parseInt(value));
              }}
            />
          </label>
          : null
      }
    </div>
  )
}
CanNetCommand.propTypes = {
  setCanNetState: PropTypes.func.isRequired,
  seconds: PropTypes.number.isRequired,
  setSeconds: PropTypes.func.isRequired,
};

const RemoteIgnitionCommand = ({ ignitionState, setIgnitionState, setSeconds, seconds }) => {
  return (
    <div>
      <Grid component="label" container alignItems="center" spacing={1}>
        <Grid item>Off</Grid>
        <Grid item>
          <Switch checked={ignitionState} onChange={(event) => {
            setIgnitionState(event.target.checked)
          }} />
        </Grid>
        <Grid item>On</Grid>
      </Grid>
      {
        ignitionState ?
          <label>
            Enter amount of seconds:
            <input
              type="number"
              value={seconds}
              min={0} // Minimum value
              step={10} // Increment/decrement step
              onChange={(event) => {
                const value = event.target.value;
                setSeconds(parseInt(value));
              }}
            />
          </label>
          : null
      }
    </div>
  )
}
RemoteIgnitionCommand.propTypes = {
  ignitionState: PropTypes.bool.isRequired,
  setIgnitionState: PropTypes.func.isRequired,
  setSeconds: PropTypes.func.isRequired,
  seconds: PropTypes.number.isRequired,
};

export default SendDiagnosticCommand;
