import DeleteIcon from "@mui/icons-material/Delete";
import {
  Alert,
  Button,
  Card,
  CardActions,
  CardContent,
  IconButton,
  Tooltip,
  Typography,
} from "@mui/material";
import Grid from "@mui/material/Grid2";
import React, { PropsWithChildren } from "react";
import { NatEntry } from "../../api/NetworksApi";
import { ServerApi } from "../../api/ServerApi";
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
import { IPInput } from "./IPInput";
import { PortInput } from "./PortInput";
import { RadioGroupInput } from "./RadioGroupInput";
import { SelectInput } from "./SelectInput";
import { TextInput } from "./TextInput";

export function NetNatConfiguration(p: {
  editable: boolean;
  nat: NatEntry[];
  nicsList: string[];
  onChange?: (nat: NatEntry[]) => void;
  version: 4 | 6;
}): React.ReactElement {
  const confirm = useConfirm();

  const addEntry = () => {
    p.nat.push({
      host_ip: {
        type: "ip",
        ip: p.version === 4 ? "10.0.0.1" : "fd00::",
      },
      host_port: { type: "single", port: 80 },
      guest_ip: p.version === 4 ? "10.0.0.100" : "fd00::",
      guest_port: 10,
      protocol: "TCP",
    });
    p.onChange?.(p.nat);
  };

  const onDelete = async (idx: number) => {
    if (!(await confirm("Do you really want to delete this entry?"))) return;

    p.nat.splice(idx, 1);
    p.onChange?.(p.nat);
  };

  return (
    <>
      {p.nat.map((e, num) => (
        <NatEntryForm
          key={num}
          {...p}
          entry={e}
          onChange={() => p.onChange?.(p.nat)}
          onDelete={() => onDelete(num)}
        />
      ))}

      {p.nat.length === 0 && (
        <Typography style={{ textAlign: "center" }}>
          You have not set any NAT entry yet.
        </Typography>
      )}

      {p.editable && <Button onClick={addEntry}>Add a new entry</Button>}
    </>
  );
}

function NatEntryForm(p: {
  editable: boolean;
  version: 4 | 6;
  entry: NatEntry;
  onChange?: () => void;
  onDelete: () => void;
  nicsList: string[];
}): React.ReactElement {
  const guestPortEnd =
    p.entry.host_port.type === "range"
      ? p.entry.host_port.end - p.entry.host_port.start + p.entry.guest_port
      : undefined;

  return (
    <Card style={{ margin: "30px" }} elevation={3}>
      <CardContent>
        <Grid container>
          <NATEntryProp>
            <SelectInput
              {...p}
              label="Protocol"
              options={[
                { value: "TCP" },
                { value: "UDP" },
                { label: "TCP & UDP", value: "Both" },
              ]}
              value={p.entry.protocol}
              onValueChange={(v) => {
                p.entry.protocol = v as any;
                p.onChange?.();
              }}
            />
          </NATEntryProp>
          <NATEntryProp>
            <TextInput
              {...p}
              label="Comment"
              value={p.entry.comment}
              onValueChange={(v) => {
                p.entry.comment = v;
                p.onChange?.();
              }}
              size={ServerApi.Config.constraints.net_nat_comment_size}
            />
          </NATEntryProp>

          {/* Host conf */}
          <NATEntryProp label="Host configuration">
            <SelectInput
              {...p}
              label="Host IP address specification"
              options={[
                {
                  label: "Specific IP",
                  value: "ip",
                  description: "Use a pre-defined IP address",
                },
                {
                  label: "Network interface",
                  value: "interface",
                  description:
                    "Use active IP addresses on the selected network interface during network startup to determine host adddress",
                },
              ]}
              value={p.entry.host_ip.type}
              onValueChange={(v) => {
                p.entry.host_ip.type = v as any;
                p.onChange?.();
              }}
            />

            {p.entry.host_ip.type === "ip" && (
              <IPInput
                {...p}
                label="Host IP address"
                value={p.entry.host_ip.ip}
                onValueChange={(v) => {
                  if (p.entry.host_ip.type === "ip") p.entry.host_ip.ip = v!;
                  p.onChange?.();
                }}
              />
            )}

            {p.entry.host_ip.type === "interface" && (
              <>
                {p.editable && (
                  <Alert severity="warning" style={{ margin: "10px 0px" }}>
                    Warning! All IP addresses may not be inferred on reboot due
                    to the fact that the network hook might be executed before
                    the network interfaces are fully configured. This might lead
                    to incomplete ports exposition!
                  </Alert>
                )}
                <SelectInput
                  {...p}
                  label="Network interface"
                  value={p.entry.host_ip.name}
                  options={p.nicsList.map((n) => {
                    return {
                      value: n,
                    };
                  })}
                  onValueChange={(v) => {
                    if (p.entry.host_ip.type === "interface")
                      p.entry.host_ip.name = v!;
                    p.onChange?.();
                  }}
                />
              </>
            )}
          </NATEntryProp>

          <NATEntryProp label="Target guest configuration">
            <IPInput
              {...p}
              label="Guest IP"
              value={p.entry.guest_ip}
              onValueChange={(v) => {
                p.entry.guest_ip = v!;
                p.onChange?.();
              }}
            />
          </NATEntryProp>

          <NATEntryProp>
            <RadioGroupInput
              {...p}
              options={[
                { label: "Single port", value: "single" },
                { label: "Range of ports", value: "range" },
              ]}
              value={p.entry.host_port.type}
              onValueChange={(v) => {
                p.entry.host_port.type = v as any;
                p.onChange?.();
              }}
            />

            {p.entry.host_port.type === "single" && (
              <PortInput
                {...p}
                label="Host port"
                value={p.entry.host_port.port}
                onChange={(v) => {
                  if (p.entry.host_port.type === "single")
                    p.entry.host_port.port = v!;
                  p.onChange?.();
                }}
              />
            )}

            {p.entry.host_port.type === "range" && (
              <div style={{ display: "flex" }}>
                <PortInput
                  {...p}
                  label="Host port start"
                  value={p.entry.host_port.start}
                  onChange={(v) => {
                    if (p.entry.host_port.type === "range")
                      p.entry.host_port.start = v!;
                    p.onChange?.();
                  }}
                />
                <PortSpacer />
                <PortInput
                  {...p}
                  label="Host port end"
                  value={p.entry.host_port.end}
                  onChange={(v) => {
                    if (p.entry.host_port.type === "range")
                      p.entry.host_port.end = v!;
                    p.onChange?.();
                  }}
                />
              </div>
            )}
          </NATEntryProp>

          <NATEntryProp>
            <div style={{ display: "flex", height: "100%", alignItems: "end" }}>
              <PortInput
                {...p}
                label={`Guest port ${guestPortEnd ? "start" : ""}`}
                value={p.entry.guest_port}
                onChange={(v) => {
                  p.entry.guest_port = v!;
                  p.onChange?.();
                }}
              />
              {guestPortEnd && <PortSpacer />}
              {guestPortEnd && (
                <PortInput
                  editable={false}
                  label={`Guest port end`}
                  value={guestPortEnd}
                  onChange={(v) => {
                    p.entry.guest_port = v!;
                    p.onChange?.();
                  }}
                />
              )}
            </div>
          </NATEntryProp>
        </Grid>
      </CardContent>
      <CardActions>
        {p.editable && (
          <Tooltip title="Remove the entry">
            <IconButton color="error" onClick={p.onDelete}>
              <DeleteIcon />
            </IconButton>
          </Tooltip>
        )}
      </CardActions>
    </Card>
  );
}

function NATEntryProp(
  p: PropsWithChildren<{ label?: string }>
): React.ReactElement {
  return (
    <Grid size={{ sm: 12, md: 6 }} style={{ padding: "20px" }}>
      {p.label && (
        <Typography variant="h6" style={{ marginBottom: "10px" }}>
          {p.label}
        </Typography>
      )}
      {p.children}
    </Grid>
  );
}

function PortSpacer(): React.ReactElement {
  return <span style={{ width: "20px" }}></span>;
}
