import {
  Alert,
  AlertIcon,
  Box,
  Button,
  Heading,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalFooter,
  ModalHeader,
  ModalOverlay,
  StackDivider,
  Table,
  TableCaption,
  TableContainer,
  Tbody,
  Td,
  Th,
  Thead,
  Tr,
  useDisclosure,
  useToast,
  VStack,
} from "@chakra-ui/react";
import { useLoaderData } from "@remix-run/react";
import { useEffect, useState } from "react";

export async function loader({ context }: { context: RequestContext }) {
  const now = new Date();
  let month = now.getUTCMonth();
  let year = now.getUTCFullYear();

  if (month === 0) {
    month = 12;
    year--;
  }

  const data = await context.data.prisma.event.findMany({
    orderBy: {
      day: "asc",
    },
    select: {
      answered_at: true,
      day: true,
      details: true,
      id: true,
      performed_at: true,
      reached_minimum_player_count: true,
      type: true,
    },
    where: {
      AND: {
        approved: true,
        month,
        year,
        OR: [
          {
            AND: [
              {
                reached_minimum_player_count: false,
                type: "gamenight",
              },
            ],
          },
        ],
      },
    },
  });

  return {
    events: data,
    past_cutoff: now.getUTCDate() > 7,
  };
}

export default function () {
  const { events, past_cutoff } = useLoaderData<typeof loader>();
  const { isOpen, onClose, onOpen } = useDisclosure();
  const [eventData, setEventData] = useState({} as (typeof events)[number]);
  const [isBrowserSupported, setIsBrowserSupported] = useState(true);
  const toast = useToast();

  useEffect(() => {
    if (typeof structuredClone === "undefined") setIsBrowserSupported(false);
  }, []);

  async function displayErrorToast(response: Response, title: string) {
    let msg = "Unknown error";

    try {
      msg = ((await response.json()) as { error: string }).error;
    } catch {}

    toast({
      description: msg,
      status: "error",
      title,
    });
  }

  function getStatus(event: (typeof events)[number]) {
    if (!event.performed_at) return "Approved";
    if (event.type === "rotw" && event.answered_at) return "Solved";
    if (event.type === "gamenight" && event.reached_minimum_player_count)
      return "Certified";

    return "Completed";
  }

  async function certify() {
    const response = await fetch(
      `/api/events-team/events/${eventData.id}/certify`,
      {
        body: "{}",
        headers: {
          "content-type": "application/json",
        },
        method: "POST",
      },
    );

    if (!response.ok) {
      await displayErrorToast(response, "Failed to certify game night");
      return;
    }

    toast({
      status: "success",
      title: "Game night certified",
    });

    const newData = structuredClone(eventData);
    newData.reached_minimum_player_count = true;

    setEventData(newData);
  }

  async function completed() {
    const response = await fetch(
      `/api/events-team/events/${eventData.id}/complete`,
      {
        body: "{}",
        headers: {
          "content-type": "application/json",
        },
        method: "POST",
      },
    );

    if (!response.ok) {
      await displayErrorToast(response, "Failed to mark as completed");
      return;
    }

    toast({
      status: "success",
      title: "Event marked as complete",
    });

    const newData = structuredClone(eventData);

    setEventData(
      Object.defineProperty(newData, "performed_at", {
        value: new Date().toISOString(),
      }),
    );
  }

  async function forgotten() {
    const response = await fetch(
      `/api/events-team/events/${eventData.id}/forgotten`,
      {
        body: "{}",
        headers: {
          "content-type": "application/json",
        },
        method: "POST",
      },
    );

    if (!response.ok) {
      await displayErrorToast(response, "Failed to mark as forgotten");
      return;
    }

    toast({
      title: "Event marked as forgotten",
      status: "success",
    });

    const newData = structuredClone(eventData);

    setEventData(
      Object.defineProperty(newData, "performed_at", {
        value: new Date().toISOString(),
      }),
    );
  }

  async function solve() {
    const response = await fetch(
      `/api/events-team/events/${eventData.id}/solve`,
      {
        body: "{}",
        headers: {
          "content-type": "application/json",
        },
        method: "POST",
      },
    );

    if (!response.ok) {
      await displayErrorToast(response, "Failed to mark as solved");
      return;
    }

    toast({
      status: "success",
      title: "Riddle marked as solved",
    });

    const newData = structuredClone(eventData);

    setEventData(
      Object.defineProperty(newData, "performed_at", {
        value: new Date().toISOString(),
      }),
    );
  }

  return (
    <>
      <Alert display={past_cutoff ? undefined : "none"} status="warning">
        <AlertIcon />
        The cutoff period for retroactively actioning events has passed.
      </Alert>
      <Alert display={isBrowserSupported ? "none" : undefined} status="error">
        <AlertIcon />
        This browser is unsupported. Please upgrade to a browser not several
        years out of date.
      </Alert>
      <Modal isOpen={isOpen} onClose={onClose}>
        <ModalOverlay />
        <ModalContent>
          <ModalHeader>Action Menu</ModalHeader>
          <ModalCloseButton />
          <ModalBody>
            <VStack divider={<StackDivider />}>
              <Box gap="8px">
                <Heading size="xs">Completion</Heading>
                <Button
                  disabled={Boolean(eventData.performed_at)}
                  onClick={async () => await completed()}
                >
                  Mark as Complete
                </Button>
                <Button
                  disabled={typeof eventData.performed_at === "number"}
                  onClick={async () => await forgotten()}
                >
                  Mark as Forgotten
                </Button>
              </Box>
              {eventData.type === "rotw" ? (
                <Box gap="8px">
                  <Heading size="xs">Solved Status</Heading>
                  <Button
                    disabled={Boolean(eventData.answered_at)}
                    onClick={async () => await solve()}
                  >
                    {eventData.answered_at ? "Solved" : "Mark as Solved"}
                  </Button>
                </Box>
              ) : null}
              {eventData.type === "gamenight" ? (
                <Box gap="8px">
                  <Heading size="xs">Certified Status</Heading>
                  <Button
                    disabled={eventData.reached_minimum_player_count}
                    onClick={async () => await certify()}
                  >
                    {eventData.reached_minimum_player_count
                      ? "Certified"
                      : "Certify"}
                  </Button>
                </Box>
              ) : null}
            </VStack>
          </ModalBody>
          <ModalFooter>
            <Button onClick={onClose}>Close</Button>
          </ModalFooter>
        </ModalContent>
      </Modal>
      <TableContainer>
        <Table variant="simple">
          <TableCaption>
            Events that are not denied or left pending which need to be actioned
          </TableCaption>
          <Thead>
            <Tr>
              <Th>Day</Th>
              <Th>Details</Th>
              <Th>Current Status</Th>
              <Th>Action</Th>
            </Tr>
          </Thead>
          <Tbody>
            {events.map((event) => (
              <Tr>
                <Td>{event.day}</Td>
                <Td>
                  {event.details.length > 100
                    ? `${event.details.substring(0, 97)}...`
                    : event.details}
                </Td>
                <Td>{getStatus(event)}</Td>
                <Td>
                  <Button
                    disabled={past_cutoff}
                    onClick={() => {
                      setEventData(event);
                      onOpen();
                    }}
                  >
                    Action Menu
                  </Button>
                </Td>
              </Tr>
            ))}
          </Tbody>
        </Table>
      </TableContainer>
    </>
  );
}
