import {
  Body1,
  Button,
  Caption1,
  Card,
  CardFooter,
  CardHeader,
  CardPreview,
  Spinner,
  Tooltip,
  makeStyles,
  typographyStyles,
} from "@fluentui/react-components";
import {
  ArrowResetRegular,
  DesktopRegular,
  PauseRegular,
  Play16Regular,
  PowerRegular,
  StopRegular,
} from "@fluentui/react-icons";
import { filesize } from "filesize";
import React from "react";
import { Rights } from "../api/ServerApi";
import { VMApi, VMInfo, VMInfoAndCaps, VMState } from "../api/VMApi";
import { useConfirm } from "../hooks/providers/ConfirmDialogProvider";
import { useToast } from "../hooks/providers/ToastProvider";
import { SectionContainer } from "./SectionContainer";
import { VMLiveScreenshot } from "./VMLiveScreenshot";

const useStyles = makeStyles({
  body1Stronger: typographyStyles.body1Stronger,
  caption1: typographyStyles.caption1,
});

export function VirtualMachinesWidget(p: {
  rights: Rights;
}): React.ReactElement {
  return (
    <SectionContainer>
      <div
        style={{
          display: "flex",
          flexDirection: "row",
          flexWrap: "wrap",
          justifyContent: "center",
        }}
      >
        {p.rights.vms.map((v, n) => (
          <VMWidget key={n} vm={v} />
        ))}
      </div>
    </SectionContainer>
  );
}

function VMWidget(p: { vm: VMInfoAndCaps }): React.ReactElement {
  const toast = useToast();

  const [state, setState] = React.useState<VMState | undefined>();

  const styles = useStyles();

  const load = async () => {
    const newState = await VMApi.State(p.vm);
    if (state !== newState) setState(newState);
  };

  React.useEffect(() => {
    const interval = setInterval(async () => {
      try {
        if (p.vm.can_get_state) await load();
      } catch (e) {
        console.error(e);
        toast("Error", `Failed to refresh ${p.vm.name} status!`, "error");
      }
    }, 1000);
    return () => clearInterval(interval);
  });

  return (
    <Card
      style={{
        width: "400px",
        maxWidth: "49%",
        height: "400px",
        margin: "10px",
        display: "flex",
        flexDirection: "column",
      }}
    >
      <CardPreview style={{ height: "150px", display: "flex" }}>
        <VMPreview {...p} state={state} />
      </CardPreview>

      <CardHeader
        image={<DesktopRegular fontSize={32} />}
        header={
          <Body1>
            <b>{p.vm.name}</b>
          </Body1>
        }
        description={
          <Caption1>
            {p.vm.can_get_state ? state ?? "..." : "Unavailable"}
          </Caption1>
        }
      />
      <p className={styles.caption1} style={{ margin: "0px auto" }}>
        {p.vm.architecture} &bull; RAM : {filesize(p.vm.memory)}{" "}
        &bull; {p.vm.number_vcpu} vCPU
      </p>

      <p style={{ flex: 1 }}>{p.vm.description}</p>

      <CardFooter style={{ flexWrap: "wrap" }}>
        <VMAction
          {...p}
          primary
          label="Start"
          icon={<Play16Regular />}
          enabled={p.vm.can_start}
          currState={state}
          possibleStates={["Shutdown", "Shutoff", "Crashed"]}
          onClick={VMApi.StartVM}
        />
        <VMAction
          {...p}
          primary
          label="Resume"
          icon={<Play16Regular />}
          enabled={p.vm.can_resume}
          currState={state}
          possibleStates={["Paused", "PowerManagementSuspended"]}
          onClick={VMApi.ResumeVM}
        />
        <VMAction
          {...p}
          primary
          label="Suspend"
          icon={<PauseRegular />}
          enabled={p.vm.can_suspend}
          currState={state}
          possibleStates={["Running"]}
          onClick={VMApi.SuspendVM}
        />
        <VMAction
          confirmAction
          {...p}
          label="Shutdown"
          icon={<PowerRegular />}
          enabled={p.vm.can_shutdown}
          currState={state}
          possibleStates={["Running"]}
          onClick={VMApi.ShutdownVM}
        />
        <VMAction
          confirmAction
          {...p}
          label="Kill"
          icon={<StopRegular />}
          enabled={p.vm.can_kill}
          currState={state}
          possibleStates={[
            "Running",
            "Paused",
            "PowerManagementSuspended",
            "Blocked",
          ]}
          onClick={VMApi.KillVM}
        />
        <VMAction
          confirmAction
          {...p}
          label="Reset"
          icon={<ArrowResetRegular />}
          enabled={p.vm.can_reset}
          currState={state}
          possibleStates={[
            "Running",
            "Paused",
            "PowerManagementSuspended",
            "Blocked",
          ]}
          onClick={VMApi.ResetVM}
        />
      </CardFooter>
    </Card>
  );
}

function VMPreview(p: {
  vm: VMInfoAndCaps;
  state?: VMState;
}): React.ReactElement {
  const styles = useStyles();
  if (!p.vm.can_screenshot || p.state !== "Running") {
    return (
      <div
        style={{
          flex: "1",
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        <span className={styles.body1Stronger}>{p.vm.name}</span>
      </div>
    );
  }

  return <VMLiveScreenshot {...p} />;
}

function VMAction(p: {
  confirmAction?: boolean;
  vm: VMInfo;
  label: string;
  primary?: boolean;
  icon: React.ReactElement;
  enabled: boolean;
  currState?: VMState;
  possibleStates: VMState[];
  onClick: (vm: VMInfo) => Promise<void>;
}): React.ReactElement {
  const toast = useToast();
  const confirm = useConfirm();

  const [loading, setLoading] = React.useState(false);

  const onClick = async () => {
    try {
      if (
        p.confirmAction &&
        !(await confirm(
          `Do you really want to ${p.label} the VM '${p.vm.name}'?`
        ))
      )
        return;

      setLoading(true);

      await p.onClick(p.vm);

      toast(p.label, `Action successfully executed!`, "success");
    } catch (e) {
      console.error(e);
      toast(p.label, `Failed to perform action: ${e}`, "error");
    } finally {
      setLoading(false);
    }
  };

  if (!p.currState || !p.possibleStates.includes(p.currState)) {
    return <></>;
  }

  if (!p.enabled)
    return (
      <Tooltip content={"Unavailable"} relationship="label">
        <Button
          appearance={p.primary ? "primary" : undefined}
          icon={p.icon}
          disabled
        >
          {p.label}
        </Button>
      </Tooltip>
    );

  return (
    <Button
      appearance={p.primary ? "primary" : undefined}
      icon={loading ? <Spinner size="tiny" /> : p.icon}
      onClick={onClick}
    >
      {p.label}
    </Button>
  );
}
