import { mdiHarddiskPlus } from "@mdi/js";
import Icon from "@mdi/react";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import DeleteIcon from "@mui/icons-material/Delete";
import { Button, IconButton, Paper, Tooltip } from "@mui/material";
import React from "react";
import { DiskImage } from "../../api/DiskImageApi";
import { ServerApi } from "../../api/ServerApi";
import { VMFileDisk, VMInfo, VMState } from "../../api/VMApi";
import { ConvertDiskImageDialog } from "../../dialogs/ConvertDiskImageDialog";
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
import { VMDiskFileWidget } from "../vms/VMDiskFileWidget";
import { CheckboxInput } from "./CheckboxInput";
import { DiskBusSelect } from "./DiskBusSelect";
import { DiskImageSelect } from "./DiskImageSelect";
import { SelectInput } from "./SelectInput";
import { TextInput } from "./TextInput";

export function VMDisksList(p: {
  vm: VMInfo;
  state?: VMState;
  onChange?: () => void;
  editable: boolean;
  diskImagesList: DiskImage[];
}): React.ReactElement {
  const [currBackupRequest, setCurrBackupRequest] = React.useState<
    VMFileDisk | undefined
  >();

  const addNewDisk = () => {
    p.vm.file_disks.push({
      format: "QCow2",
      size: 10000 * 1000 * 1000,
      bus: "Virtio",
      delete: false,
      name: `disk${p.vm.file_disks.length}`,
      new: true,
    });
    p.onChange?.();
  };

  const handleBackupRequest = (disk: VMFileDisk) => {
    setCurrBackupRequest(disk);
  };

  const handleFinishBackup = () => {
    setCurrBackupRequest(undefined);
  };

  return (
    <>
      {/* disks list */}
      {p.vm.file_disks.map((d, num) => (
        <DiskInfo
          // eslint-disable-next-line react-x/no-array-index-key
          key={num}
          editable={p.editable}
          canBackup={!p.editable && !d.new && p.state !== "Running"}
          disk={d}
          onChange={p.onChange}
          removeFromList={() => {
            p.vm.file_disks.splice(num, 1);
            p.onChange?.();
          }}
          onRequestBackup={handleBackupRequest}
          diskImagesList={p.diskImagesList}
        />
      ))}

      {p.editable && <Button onClick={addNewDisk}>Add new disk</Button>}

      {/* Disk backup */}
      {currBackupRequest && (
        <ConvertDiskImageDialog
          backup
          onCancel={handleFinishBackup}
          onFinished={handleFinishBackup}
          vm={p.vm}
          disk={currBackupRequest}
        />
      )}
    </>
  );
}

function DiskInfo(p: {
  editable: boolean;
  canBackup: boolean;
  disk: VMFileDisk;
  onChange?: () => void;
  removeFromList: () => void;
  onRequestBackup: (disk: VMFileDisk) => void;
  diskImagesList: DiskImage[];
}): React.ReactElement {
  const confirm = useConfirm();
  const deleteDisk = async () => {
    if (p.disk.deleteType) {
      p.disk.deleteType = undefined;
      p.onChange?.();
      return;
    }

    const keepFile = await confirm(
      `You asked to delete the disk ${p.disk.name}. Do you want to keep the block file or not ? `,
      "Delete disk",
      "Keep the file",
      "Delete the file"
    );

    if (!(await confirm("Do you really want to delete this disk?"))) return;

    p.disk.deleteType = keepFile ? "keepfile" : "deletefile";
    p.onChange?.();
  };

  if (!p.editable || !p.disk.new)
    return (
      <VMDiskFileWidget
        {...p}
        secondaryAction={
          <>
            {p.editable && (
              <IconButton
                edge="end"
                aria-label="delete disk"
                onClick={deleteDisk}
              >
                {p.disk.deleteType ? (
                  <Tooltip title="Cancel disk removal">
                    <CheckCircleIcon />
                  </Tooltip>
                ) : (
                  <Tooltip title="Remove disk">
                    <DeleteIcon />
                  </Tooltip>
                )}
              </IconButton>
            )}

            {p.canBackup && (
              <Tooltip title="Backup this disk">
                <IconButton
                  onClick={() => {
                    p.onRequestBackup(p.disk);
                  }}
                >
                  <Icon path={mdiHarddiskPlus} size={1} />
                </IconButton>
              </Tooltip>
            )}
          </>
        }
      />
    );

  return (
    <Paper elevation={3} style={{ margin: "10px", padding: "10px" }}>
      <div style={{ display: "flex", justifyContent: "space-between" }}>
        <TextInput
          editable={true}
          label="Disk name"
          size={ServerApi.Config.constraints.disk_name_size}
          checkValue={(v) => /^[a-zA-Z0-9]+$/.test(v)}
          value={p.disk.name}
          onValueChange={(v) => {
            p.disk.name = v ?? "";
            p.onChange?.();
          }}
        />
        <IconButton onClick={p.removeFromList}>
          <DeleteIcon />
        </IconButton>
      </div>

      <SelectInput
        editable={true}
        label="Disk format"
        options={[
          { label: "Raw file", value: "Raw" },
          { label: "QCow2", value: "QCow2" },
        ]}
        value={p.disk.format}
        onValueChange={(v) => {
          p.disk.format = v as any;

          if (p.disk.format === "Raw") p.disk.is_sparse = true;

          p.onChange?.();
        }}
      />

      {/* Bus selection */}
      <DiskBusSelect
        editable
        value={p.disk.bus}
        onValueChange={(v) => {
          p.disk.bus = v;
          p.onChange?.();
        }}
      />

      {/* Raw disk: choose sparse mode */}
      {p.disk.format === "Raw" && (
        <CheckboxInput
          editable
          label="Sparse file"
          checked={p.disk.is_sparse}
          onValueChange={(v) => {
            if (p.disk.format === "Raw") p.disk.is_sparse = v;
            p.onChange?.();
          }}
        />
      )}

      <TextInput
        editable={true}
        label="Disk size (GB)"
        size={{
          min:
            ServerApi.Config.constraints.disk_size.min / (1000 * 1000 * 1000),
          max:
            ServerApi.Config.constraints.disk_size.max / (1000 * 1000 * 1000),
        }}
        value={(p.disk.size / (1000 * 1000 * 1000)).toString()}
        onValueChange={(v) => {
          p.disk.size = Number(v ?? "0") * 1000 * 1000 * 1000;
          p.onChange?.();
        }}
        type="number"
        disabled={!!p.disk.from_image}
      />

      <DiskImageSelect
        label="Use disk image as template"
        list={p.diskImagesList}
        value={p.disk.from_image}
        onValueChange={(v) => {
          p.disk.from_image = v;
          p.onChange?.();
        }}
      />
    </Paper>
  );
}
