import React, { useEffect, useState } from "react";

import { LoadingButton, LoadingButtonProps } from "@mui/lab";
import { Box } from "@mui/material";
import CircularProgress from "@mui/material/CircularProgress";
import Grid from "@mui/material/Grid2";

import { useSnackbar } from "notistack";

import Card from "../../../../components/Card";
import CardActions from "../../../../components/Card/CardActions";
import CardCancelButton from "../../../../components/Card/CardCancelButton";
import { CardContent } from "../../../../components/Card/CardContent";
import CardHeader from "../../../../components/Card/CardHeader";
import CardSaveButton from "../../../../components/Card/CardSaveButton";
import Chip from "../../../../components/Chip";
import { useApi } from "../../../../contexts/ApiContext";
import { useCardContext } from "../../../../contexts/CardContext";
import { useDialog } from "../../../../contexts/DialogContext";
import { useUser } from "../../../../contexts/UserContext";
import { hasPermission } from "../../../../util/has_permission";
import type { OrderDetail, OrderItem, OrderListItem } from "../../types/order";
import RecipientCard from "../RecipientCard";
import ShipmentCard from "../ShipmentCard";

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

export interface OrderDetailProps {
  order: OrderListItem;
}

const OrderDetail: React.FC<OrderDetailProps> = ({ order }) => {
  const api = useApi();
  const { enqueueSnackbar } = useSnackbar();
  const [details, setDetails] = useState<OrderDetail | null>(null);
  const [buttonsLoading, setButtonsLoading] = useState(false);
  const [selected, setSelected] = useState<OrderItem[]>([]);
  const { user } = useUser();

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

  useEffect(() => {
    if (details == null) loadDetails();
  });

  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 = () => {
    const { isEditing } = useCardContext();
    if (details == null) return null;

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

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

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

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

    return null;
  };

  return details != null ? (
    <Grid container spacing={2}>
      <Grid size={{ xs: 12 }}>
        <Card isEditable={details.destination_type === "STORE" && details.state === "PENDING"}>
          <CardHeader
            action={
              <Grid container spacing={2}>
                <Grid sx={{ mt: 0.5 }}>
                  {details.channel ? <Chip label={details.channel} sx={{ mr: 1 }} /> : null}
                  <OrderStateChip element={details} sx={{ mr: 1 }} />
                </Grid>
              </Grid>
            }
            sx={{
              borderBottomWidth: 1,
              borderBottomStyle: "solid",
              borderBottomColor: "divider",
            }}
            title="Order"
          >
            {details.channel ? <Chip label={details.channel} sx={{ mr: 1 }} /> : null}
            <OrderStateChip element={details} sx={{ mr: 1 }} />
          </CardHeader>
          <CardContent sx={{ padding: 0 }}>
            <OrderItemsTable
              isPending={details.state === "PENDING"}
              items={details.items}
              onSelect={setSelected}
            />
          </CardContent>
          {hasPermission(user, "fulfillment.change_order") && (
            <CardActions>
              <Box sx={{ width: "100%" }}>
                <CancelOrderButton isPending={details.state === "PENDING"} onClick={doCancel} />
              </Box>

              <CardCancelButton />
              <CardSaveButton />
              <StatusButton />
            </CardActions>
          )}
        </Card>
      </Grid>

      <Grid size={{ xs: 4 }}>
        <OrderDestinationCard order={details} />
      </Grid>

      {details.shipment ? (
        <Grid size={{ xs: 4 }}>
          <ShipmentCard shipment={details.shipment} />
        </Grid>
      ) : null}

      {details.recipient ? (
        <Grid size={{ xs: 4 }}>
          <RecipientCard
            email={details.email}
            phone={details.phone}
            recipient={details.recipient}
          />
        </Grid>
      ) : null}
    </Grid>
  ) : (
    <CircularProgress color="secondary" />
  );
};

export default OrderDetail;
