import {
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
} from "@mui/material";
import React from "react";
import { DiskImage, DiskImageApi, DiskImageFormat } from "../api/DiskImageApi";
import { ServerApi } from "../api/ServerApi";
import { VMFileDisk, VMInfo } from "../api/VMApi";
import { useAlert } from "../hooks/providers/AlertDialogProvider";
import { useLoadingMessage } from "../hooks/providers/LoadingMessageProvider";
import { FileDiskImageWidget } from "../widgets/FileDiskImageWidget";
import { CheckboxInput } from "../widgets/forms/CheckboxInput";
import { SelectInput } from "../widgets/forms/SelectInput";
import { TextInput } from "../widgets/forms/TextInput";
import { VMDiskFileWidget } from "../widgets/vms/VMDiskFileWidget";

export function ConvertDiskImageDialog(
  p: {
    onCancel: () => void;
    onFinished: () => void;
  } & (
    | { backup?: false; image: DiskImage }
    | { backup: true; disk: VMFileDisk; vm: VMInfo }
  )
): React.ReactElement {
  const alert = useAlert();
  const loadingMessage = useLoadingMessage();

  const [format, setFormat] = React.useState<DiskImageFormat>({
    format: "QCow2",
  });

  const origFilename = p.backup ? p.disk.name : p.image.file_name;

  const [filename, setFilename] = React.useState(origFilename + ".qcow2");

  const handleFormatChange = (value?: string) => {
    setFormat({ format: value ?? ("QCow2" as any) });

    if (value === "QCow2") setFilename(`${origFilename}.qcow2`);
    if (value === "GzCompressedQCow2") setFilename(`${origFilename}.qcow2.gz`);
    if (value === "XzCompressedQCow2") setFilename(`${origFilename}.qcow2.xz`);
    if (value === "Raw") {
      setFilename(`${origFilename}.raw`);
      // Check sparse checkbox by default
      setFormat({ format: "Raw", is_sparse: true });
    }
    if (value === "GzCompressedRaw") setFilename(`${origFilename}.raw.gz`);
    if (value === "XzCompressedRaw") setFilename(`${origFilename}.raw.xz`);
  };

  const handleSubmit = async () => {
    try {
      loadingMessage.show(
        p.backup ? "Performing backup..." : "Converting image..."
      );

      // Perform the conversion / backup operation
      if (p.backup)
        await DiskImageApi.BackupVMDisk(p.vm, p.disk, filename, format);
      else await DiskImageApi.Convert(p.image, filename, format);

      p.onFinished();

      alert(p.backup ? "Backup successful!" : "Conversion successful!");
    } catch (e) {
      console.error("Failed to perform backup/conversion!", e);
      alert(
        p.backup
          ? `Failed to perform backup! ${e}`
          : `Failed to convert image! ${e}`
      );
    } finally {
      loadingMessage.hide();
    }
  };

  return (
    <Dialog open onClose={p.onCancel}>
      <DialogTitle>
        {p.backup ? `Backup disk ${p.disk.name}` : "Convert disk image"}
      </DialogTitle>

      <DialogContent>
        <DialogContentText>
          Select the destination format for this image:
        </DialogContentText>

        {/* Show details of of the image */}
        {p.backup ? (
          <VMDiskFileWidget {...p} />
        ) : (
          <FileDiskImageWidget {...p} />
        )}

        {/* New image format */}
        <SelectInput
          editable
          label="Target format"
          value={format.format}
          onValueChange={handleFormatChange}
          options={[
            { value: "QCow2" },
            { value: "Raw" },
            { value: "GzCompressedRaw" },
            { value: "XzCompressedRaw" },
            { value: "GzCompressedQCow2" },
            { value: "XzCompressedQCow2" },
          ]}
        />

        {/* Check for sparse file */}
        {format.format === "Raw" && (
          <CheckboxInput
            editable
            label="Sparse file"
            checked={format.is_sparse}
            onValueChange={(c) => {
              setFormat({ format: "Raw", is_sparse: c });
            }}
          />
        )}

        {/* New image name */}
        <TextInput
          editable
          label="New image name"
          value={filename}
          onValueChange={(s) => {
            setFilename(s ?? "");
          }}
          size={ServerApi.Config.constraints.disk_image_name_size}
          helperText="The image name shall contain the proper file extension for the selected target format"
        />
      </DialogContent>
      <DialogActions>
        <Button onClick={p.onCancel}>Cancel</Button>
        <Button onClick={handleSubmit} autoFocus>
          {p.backup ? "Perform backup" : "Convert image"}
        </Button>
      </DialogActions>
    </Dialog>
  );
}
