import React from "react";

import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { LoadingButton, LoadingButtonProps } from "@mui/lab";
import Accordion from "@mui/material/Accordion";
import AccordionActions from "@mui/material/AccordionActions";
import AccordionDetails from "@mui/material/AccordionDetails";
import AccordionSummary from "@mui/material/AccordionSummary";
import Button from "@mui/material/Button";
import CircularProgress from "@mui/material/CircularProgress";
import { useTheme } from "@mui/material/styles";
import Typography from "@mui/material/Typography";

import { useSnackbar } from "notistack";

import Card from "../../../../components/Card";
import { useApi } from "../../../../contexts/ApiContext";
import { useDialog } from "../../../../contexts/DialogContext";
import { formatPurchaseNumber } from "../../../../util/format_purchase_number";
import { OrderDetail, OrderItem, OrderListItem } from "../../types/order";

import OrderItemsTable from "./OrderItemsTable";
import OrderStateChip from "./OrderStateChip";

interface OrderAccordionProps {
  order: OrderListItem;
}

const OrderAccordion: React.FC<OrderAccordionProps> = ({ order }) => {
  const api = useApi();
  const theme = useTheme();
  const { enqueueSnackbar } = useSnackbar();
  const [details, setDetails] = React.useState<OrderDetail | null>(null);
  const [buttonsLoading, setButtonsLoading] = React.useState(false);
  const [selected, setSelected] = React.useState<OrderItem[]>([]);
  const title = [
    formatPurchaseNumber(order.purchase_number),
    order.recipient && order.recipient?.given_name + " " + order.recipient?.family_name,
    order.email,
    order.phone,
  ]
    .map((v) => v?.trim())
    .filter(Boolean)
    .join(" • ");

  const loadDetails = () => {
    setDetails(null);
    api.operations["fulfillment.order:detail"]
      .call({
        params: {
          reference: order.reference,
        },
      })
      .then(async (response) => setDetails(await response.json()));
  };

  const openDialog = useDialog();

  const markAsArrived = async () => {
    if (
      !(await openDialog(
        "Are you sure?",
        "This will notify the customer that the order is ready for pick up",
      ))
    ) {
      return;
    }
    setButtonsLoading(true);
    api.operations["fulfillment.order:ready-for-pickup"]
      .call({
        params: { reference: order.reference },
        body: selected,
      })
      .then((response) => {
        if (response.ok) {
          enqueueSnackbar("Order is now ready for pickup", {
            variant: "success",
          });
        } else {
          enqueueSnackbar("Failed to mark order as ready for pickup", {
            variant: "error",
          });
          throw response;
        }
      })
      .finally(() => {
        setButtonsLoading(false);
        loadDetails();
      });
  };

  const markAsDelivered = async () => {
    if (!(await openDialog("Are you sure?", "This will mark the order as delivered"))) {
      return;
    }
    setButtonsLoading(true);
    api.operations["fulfillment.order:delivered"]
      .call({
        params: { reference: order.reference },
      })
      .then((response) => {
        if (response.ok) {
          enqueueSnackbar("Successfully marked order as delivered", {
            variant: "success",
          });
        } else {
          enqueueSnackbar("Failed to mark order as delivered", {
            variant: "error",
          });
          throw response;
        }
      })
      .finally(() => {
        setButtonsLoading(false);
        loadDetails();
      });
  };

  const doCancel = async () => {
    if (
      !(await openDialog(
        "Are you sure?",
        "This will fully cancel the order and release the authorized payment back to the customer",
      ))
    ) {
      return;
    }
    api.operations["fulfillment.order:cancel"]
      .call({
        params: { reference: order.reference },
      })
      .then((response) => {
        if (response.ok) {
          enqueueSnackbar("Order cancelled", {
            variant: "success",
          });
        } else {
          enqueueSnackbar("Failed to cancel order", {
            variant: "error",
          });
          throw response;
        }
      })
      .finally(() => {
        setButtonsLoading(false);
        loadDetails();
      });
  };

  const StatusButton = () => {
    if (!details) {
      return null;
    }

    const props: LoadingButtonProps = {
      variant: "contained",
      color: "primary",
      loading: buttonsLoading,
      disabled: buttonsLoading,
    };

    if (["DELIVERED", "CANCELLED"].includes(details.state)) {
      return null;
    }

    if (details.state === "PENDING") {
      props.disabled ||= selected.length === 0;
      return (
        <LoadingButton {...props} onClick={markAsArrived}>
          Ready for pickup
        </LoadingButton>
      );
    }

    if (["IN_TRANSIT", "READY_FOR_PICKUP", "SENT"].includes(details.state)) {
      return (
        <LoadingButton {...props} onClick={markAsDelivered}>
          Mark as Delivered
        </LoadingButton>
      );
    }

    return null;
  };

  return (
    <Accordion
      sx={{
        boxShadow: 0,
        borderRadius: `${theme.spacing(3)} !important`,
        borderWidth: "1px",
        borderStyle: "solid",
        borderColor: theme.palette.divider,
      }}
      onChange={() => (details == null ? loadDetails() : void 0)}
    >
      <AccordionSummary expandIcon={<ExpandMoreIcon />} sx={{ margin: 1 }}>
        {/* TODO: Re-enable when we implement some kind of bulk update thing
          <Checkbox
            color="secondary"
            onClick={(event) => event.stopPropagation()}
          />
        */}
        <Typography sx={{ marginY: "auto", flexGrow: 1 }}>{title}</Typography>
        <OrderStateChip element={details ?? order} sx={{ marginRight: 2 }} />
      </AccordionSummary>

      {details != null ? (
        <Card sx={{ border: "none", p: 0 }}>
          <AccordionDetails sx={{ p: 0 }}>
            <OrderItemsTable
              isPending={details.state === "PENDING"}
              items={details.items}
              onSelect={setSelected}
            />
          </AccordionDetails>

          <AccordionActions sx={{ mr: 1, mb: 1.5 }}>
            {details.state === "PENDING" ? (
              <Button color="error" variant="outlined" onClick={doCancel}>
                Cancel order
              </Button>
            ) : null}
            <StatusButton />
          </AccordionActions>
        </Card>
      ) : (
        <AccordionDetails
          sx={{
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
            minHeight: 100,
          }}
        >
          <CircularProgress color="secondary" />
        </AccordionDetails>
      )}
    </Accordion>
  );
};

export default OrderAccordion;
