import {
  Box,
  Button,
  Container,
  Flex,
  Popover,
  PopoverArrow,
  PopoverBody,
  PopoverCloseButton,
  PopoverContent,
  PopoverHeader,
  PopoverTrigger,
  Select,
  useBreakpointValue,
  useDisclosure,
  useToast,
  VStack,
} from "@chakra-ui/react";
import { useEffect, useState } from "react";
import AppealCard from "../../components/AppealCard.js";
import GameAppealCard from "../../components/GameAppealCard.js";
import NewGameBan from "../../components/NewGameBan.js";
import NewInfractionModal from "../../components/NewInfractionModal.js";
import ReportCard from "../../components/ReportCard.js";
import { useLoaderData } from "@remix-run/react";
import NewInactivityNotice from "../../components/NewInactivityNotice.js";

export async function loader({ context }: { context: RequestContext }) {
  const { current_user: currentUser } = context.data;

  if (!currentUser)
    throw new Response(null, {
      status: 401,
    });

  const departments = {
    DM: 1 << 2,
    ET: 1 << 3,
    FM: 1 << 10,
    WM: 1 << 9,
  };

  const newItemPermissions = {
    game_ban: [1 << 5],
    inactivity: [1 << 2, 1 << 9, 1 << 10],
    infraction: [1 << 0, 1 << 2, 1 << 6, 1 << 7],
  };

  const newItemNames: { [k: string]: string } = {
    game_ban: "Game Ban",
    inactivity: "Inactivity Notice",
    infraction: "Infraction",
  };

  const typePermissions = {
    appeal: [1 << 0, 1 << 1],
    gma: [1 << 5],
    report: [1 << 5],
  };

  const typeNames: { [k: string]: string } = {
    appeal: "Discord Appeals",
    gma: "Game Appeals",
    report: "Game Reports",
  };

  const allowedNewItems = [];
  const allowedTypes = [];

  for (const [item, ints] of Object.entries(newItemPermissions)) {
    if (ints.find((i) => currentUser.permissions & i))
      allowedNewItems.push({ name: newItemNames[item], value: item });
  }

  for (const [type, ints] of Object.entries(typePermissions)) {
    if (ints.find((i) => currentUser.permissions & i))
      allowedTypes.push({ name: typeNames[type], value: type });
  }

  if (!allowedTypes.length)
    throw new Response(null, {
      status: 403,
    });

  return {
    can_edit_ban_users: [
      "165594923586945025",
      "289372404541554689",
      "396347223736057866",
    ].includes(currentUser.id),
    departments: Object.entries(departments)
      .filter((d) => d[1] & currentUser.permissions)
      .map((arr) => arr[0]),
    entry_types: allowedTypes,
    item_types: allowedNewItems,
  };
}

export function meta() {
  return [
    {
      title: "Moderation Queue - Car Crushers",
    },
  ];
}

export default function () {
  const pageProps = useLoaderData<typeof loader>();
  const isDesktop = useBreakpointValue({ base: false, lg: true });
  const entryTypes = [];
  const [entries, setEntries] = useState([] as JSX.Element[]);
  const [before, setBefore] = useState(0);

  for (const type of pageProps.entry_types)
    entryTypes.push(
      <option key={type.value} value={type.value}>
        {type.name}
      </option>
    );

  async function updateQueue(
    queue_type: string,
    before = Date.now(),
    show_closed = false
  ): Promise<void> {
    const queueReq = await fetch(
      `/api/mod-queue/list?before=${before}&showClosed=${show_closed}&type=${queue_type}`
    );

    if (!queueReq.ok) {
      const errorData: { error: string } = await queueReq.json();

      useToast()({
        description: errorData.error,
        duration: 10000,
        isClosable: true,
        status: "error",
        title: "Failed to load queue",
      });

      return;
    }

    const searchParams = new URLSearchParams(location.search);
    const itemId = searchParams.get("id");
    const itemType = searchParams.get("type");

    const entryData: { [k: string]: any }[] = await queueReq.json();
    const newEntries = [...entries];

    if (itemId && itemType && ["appeal", "gma", "report"].includes(itemType)) {
      const itemReq = await fetch(`/api/mod-queue/${itemType}/${itemId}`);

      if (!itemReq.ok) {
        useToast()({
          description: ((await itemReq.json()) as { error: string }).error,
          duration: 10000,
          isClosable: true,
          status: "error",
          title: "Failed to load item with id " + itemId,
        });
      } else {
        const itemData: { [k: string]: any } = await itemReq.json();

        entryData.unshift(itemData);
      }
    }

    if (!entryData.length) return;

    for (const entry of entryData) {
      switch (queue_type) {
        case "appeal":
          newEntries.push(<AppealCard {...(entry as AppealCardProps)} />);

          break;

        case "gma":
          newEntries.push(<GameAppealCard {...(entry as GameAppealProps)} />);

          break;

        case "report":
          newEntries.push(<ReportCard {...(entry as ReportCardProps)} />);

          break;
      }
    }

    setEntries(newEntries);
    setBefore(entryData[entryData.length - 1].created_at);
  }

  const itemModals: {
    [k: string]: {
      isOpen: boolean;
      onOpen: () => void;
      onClose: () => void;
      [k: string]: any;
    };
  } = {
    game_ban: useDisclosure(),
    inactivity: useDisclosure(),
    infraction: useDisclosure(),
  };

  useEffect(() => {
    (async function () {
      await updateQueue(pageProps.entry_types[0].value);
    })();

    const searchParams = new URLSearchParams(location.search);
    const modal = searchParams.get("modal");

    if (!modal || !pageProps.item_types.find((m) => m.value === modal)) return;

    itemModals[modal].onOpen();
  }, []);

  return (
    <Container maxW="container.lg">
      <NewGameBan
        isOpen={itemModals.game_ban.isOpen}
        onClose={itemModals.game_ban.onClose}
      />
      <NewInactivityNotice
        departments={pageProps.departments}
        isOpen={itemModals.inactivity.isOpen}
        onClose={itemModals.inactivity.onClose}
      />
      <NewInfractionModal
        isOpen={itemModals.infraction.isOpen}
        onClose={itemModals.infraction.onClose}
      />
      <Flex>
        <VStack w={isDesktop ? "container.md" : "container.lg"}>
          {entries}
        </VStack>
        <Box display={isDesktop ? undefined : "none"} ml="16px" w="248px">
          <Select>{entryTypes}</Select>
        </Box>
      </Flex>
      <Popover placement="top-end">
        <PopoverTrigger>
          <Button
            borderRadius="50%"
            bottom="10vh"
            h="16"
            position="absolute"
            right="10vh"
            w="16"
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="32"
              height="32"
              fill="currentColor"
              viewBox="0 0 16 16"
            >
              <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
            </svg>
          </Button>
        </PopoverTrigger>
        <PopoverContent>
          <PopoverArrow />
          <PopoverCloseButton />
          <PopoverHeader>Create New</PopoverHeader>
          <PopoverBody>
            <VStack>
              {pageProps.item_types.map((item) => (
                <Button
                  key={item.value}
                  onClick={() => itemModals[item.value].onOpen()}
                  w="100%"
                >
                  {item.name}
                </Button>
              ))}
            </VStack>
          </PopoverBody>
        </PopoverContent>
      </Popover>
    </Container>
  );
}
