import {
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  FormControlLabel,
  IconButton,
  InputBase,
  MenuItem,
  Paper,
  Switch,
  TextField,
  Theme
} from "@mui/material";
import { createStyles } from "@mui/styles";
import withStyles, { WithStyles } from "@mui/styles/withStyles";
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
import { pond } from "protobuf-ts/pond";
import { FirmwareAPIContext } from "providers/pond/firmwareAPI";
import React from "react";
import semver from "semver";
import { or } from "utils/types";

const styles = (theme: Theme) => {
  return createStyles({
    root: {
      padding: "2px 4px",
      display: "flex",
      alignItems: "center"
    },
    input: {
      marginLeft: 8,
      flex: 1
    },
    iconButton: {
      padding: 10
    }
  });
};

interface Props extends WithStyles<typeof styles> {
  isOpen: boolean;
  closeDialogCallback: () => void;
  refreshCallback: () => void;
}

interface State {
  dirty: boolean;
  version: string;
  platform: pond.DevicePlatform;
  channel: pond.UpgradeChannel;
  file?: Blob;
  breaksStorage: boolean;
}

class UploadFirmware extends React.Component<Props, State> {
  static contextType = FirmwareAPIContext;
  declare context: React.ContextType<typeof FirmwareAPIContext>;
  selector: any;
  constructor(props: Props) {
    super(props);
    this.state = {
      dirty: false,
      version: "",
      platform: pond.DevicePlatform.DEVICE_PLATFORM_PHOTON,
      channel: pond.UpgradeChannel.UPGRADE_CHANNEL_DEVELOPMENT,
      breaksStorage: false
    };
  }

  isValid() {
    const { version, platform, channel, file } = this.state;
    var isPlatformValid = [
      pond.DevicePlatform.DEVICE_PLATFORM_PHOTON,
      pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON,
      pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR,
      pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_S3,
      pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLACK,
      pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_GREEN,
      pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLUE,
      pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_BLUE,
      pond.DevicePlatform.DEVICE_PLATFORM_V2_ETHERNET_BLUE
    ].includes(platform);
    var isChannelValid = [
      pond.UpgradeChannel.UPGRADE_CHANNEL_ALPHA,
      pond.UpgradeChannel.UPGRADE_CHANNEL_BETA,
      pond.UpgradeChannel.UPGRADE_CHANNEL_STABLE,
      pond.UpgradeChannel.UPGRADE_CHANNEL_DEVELOPMENT
    ].includes(channel);

    var isVersionValid = semver.valid(version) !== null;
    var isFileValid = file !== undefined;
    return isPlatformValid && isChannelValid && isVersionValid && isFileValid;
  }

  componentDidMount() {
    this.selector = document.createElement("input");
    this.selector.setAttribute("type", "file");
    var self = this;
    this.selector.addEventListener("change", function() {
      if (self.selector.files && self.selector.files.length > 0) {
        self.selectFile(self.selector.files[0]);
      }
    });
  }

  closeDialog = () => {
    this.props.closeDialogCallback();
  };

  openFileSelector = () => {
    this.selector.click();
  };

  prefill = (filename: string) => {
    filename = filename.toLowerCase();
    var state: State = {} as State;
    if (filename.includes("photon") || filename.includes("wifi")) {
      state.platform = pond.DevicePlatform.DEVICE_PLATFORM_PHOTON;
    }
    if (filename.includes("electron") || filename.includes("cell")) {
      state.platform = pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON;
    }
    if (filename.includes("alpha")) {
      state.channel = pond.UpgradeChannel.UPGRADE_CHANNEL_ALPHA;
    }
    if (filename.includes("beta")) {
      state.channel = pond.UpgradeChannel.UPGRADE_CHANNEL_BETA;
    }
    if (filename.includes("stable")) {
      state.channel = pond.UpgradeChannel.UPGRADE_CHANNEL_STABLE;
    }
    if (filename.includes("dev")) {
      state.channel = pond.UpgradeChannel.UPGRADE_CHANNEL_DEVELOPMENT;
    }
    var version = filename.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)*/g);
    if (version && version.length > 0) {
      state.version = version[0];
    }
    if (filename.includes("break")) {
      state.breaksStorage = true;
    }
    this.setState(state);
  };

  selectFile = (file: any) => {
    const { dirty } = this.state;
    if (!dirty) {
      this.prefill(file.name);
    }
    this.setState({ file: file });
  };

  uploadFirmware = () => {
    const { refreshCallback } = this.props;
    const { version, channel, platform, file, breaksStorage } = this.state;
    const firmwareAPI = this.context;
    if (file) {
      firmwareAPI
        .uploadFirmware(version, channel, platform, file, breaksStorage)
        .then(() => {
          this.closeDialog();
          refreshCallback();
        })
        .catch((err: any) => {
          console.error(err ? err.message : "Error occurred while uploading firmware");
        });
    } else {
      console.error("Cannot upload firmware, file not found");
    }
  };

  render() {
    const { classes, isOpen } = this.props;
    const { version, channel, platform, file } = this.state;

    return (
      <Dialog
        fullWidth
        open={isOpen}
        onClose={this.closeDialog}
        aria-labelledby="form-dialog-title">
        <DialogTitle id="form-dialog-title">Upload Firmware</DialogTitle>
        <DialogContent>
          <Paper className={classes.root} elevation={0}>
            <IconButton
              onClick={this.openFileSelector}
              className={classes.iconButton}
              aria-label="Select">
              <CloudUploadIcon />
            </IconButton>
            <InputBase
              disabled
              className={classes.input}
              placeholder="Select a binary"
              value={or(file as any, { name: "" }).name}
            />
          </Paper>
          <TextField
            id="platform"
            name="platform"
            select
            required
            label="Platform"
            margin="normal"
            fullWidth
            variant="outlined"
            value={platform}
            onChange={event =>
              this.setState({
                platform: parseInt(event.target.value) as pond.DevicePlatform,
                dirty: true
              })
            }>
            <MenuItem value={pond.DevicePlatform.DEVICE_PLATFORM_PHOTON}>Photon (Wifi)</MenuItem>
            <MenuItem value={pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON}>
              Electron (Cellular)
            </MenuItem>
            <MenuItem value={pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR}>V2 Cellular</MenuItem>
            <MenuItem value={pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_S3}>V2 Wifi S3</MenuItem>
            <MenuItem value={pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLACK}>
              V2 Cellular Black
            </MenuItem>
            <MenuItem value={pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_GREEN}>
              V2 Cellular Green
            </MenuItem>
            <MenuItem value={pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLUE}>
              V2 Cellular Blue
            </MenuItem>
            <MenuItem value={pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_BLUE}>
              V2 Wifi Blue
            </MenuItem>            
            <MenuItem value={pond.DevicePlatform.DEVICE_PLATFORM_V2_ETHERNET_BLUE}>
              V2 Ethernet Blue
            </MenuItem>
          </TextField>
          <TextField
            id="channel"
            name="channel"
            select
            required
            label="Channel"
            margin="normal"
            fullWidth
            variant="outlined"
            value={channel}
            onChange={event => {
              this.setState({
                channel: parseInt(event.target.value) as pond.UpgradeChannel,
                dirty: true
              });
            }}>
            <MenuItem value={pond.UpgradeChannel.UPGRADE_CHANNEL_RECOVERY}>Recovery</MenuItem>
            <MenuItem value={pond.UpgradeChannel.UPGRADE_CHANNEL_DEVELOPMENT}>Development</MenuItem>
            <MenuItem value={pond.UpgradeChannel.UPGRADE_CHANNEL_ALPHA}>Alpha</MenuItem>
            <MenuItem value={pond.UpgradeChannel.UPGRADE_CHANNEL_BETA}>Beta</MenuItem>
            <MenuItem value={pond.UpgradeChannel.UPGRADE_CHANNEL_STABLE}>Stable</MenuItem>
          </TextField>
          <TextField
            id="version"
            name="version"
            autoFocus
            required
            label="Version"
            margin="normal"
            type="text"
            fullWidth
            variant="outlined"
            value={version}
            onChange={event => {
              this.setState({
                version: event.target.value,
                dirty: true
              });
            }}
          />
          <FormControlLabel
            control={
              <Switch
                name="breaksStorage"
                checked={this.state.breaksStorage}
                onChange={event => {
                  this.setState({
                    breaksStorage: event.target.checked,
                    dirty: true
                  });
                }}
                color="primary"
              />
            }
            label="Breaks Storage"
          />
        </DialogContent>
        <DialogActions>
          <Button onClick={this.closeDialog} color="primary">
            Cancel
          </Button>
          <Button onClick={this.uploadFirmware} color="primary" disabled={!this.isValid()}>
            Upload
          </Button>
        </DialogActions>
      </Dialog>
    );
  }
}

export default withStyles(styles)(UploadFirmware);
