import {
  Button,
  Container,
  Divider,
  Heading,
  Link,
  ListItem,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalHeader,
  ModalOverlay,
  Stack,
  Table,
  TableCaption,
  TableContainer,
  Tbody,
  Td,
  Text,
  Th,
  Thead,
  Tr,
  UnorderedList,
  useDisclosure,
  useToast,
} from "@chakra-ui/react";
import { type Dispatch, type SetStateAction, useEffect, useState } from "react";
import { useLoaderData } from "@remix-run/react";

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

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

  const d1Promises = [];

  for (const itemType of ["appeals", "inactivity_notices", "reports"])
    d1Promises.push(
      context.env.D1.prepare(
        `SELECT *
         FROM ${itemType}
         WHERE json_extract(user, '$.id') = ?
         ORDER BY created_at DESC;`,
      )
        .bind(currentUser.id)
        .all(),
    );

  const settledPromises = await Promise.allSettled(d1Promises);
  let etData: { [k: string]: any } | null = null;

  if (currentUser.permissions & (1 << 3)) {
    etData = await context.env.D1.prepare(
      "SELECT name, points, roblox_id FROM et_members WHERE id = ?;",
    )
      .bind(currentUser.id)
      .first();
  }

  return {
    etData,
    items: settledPromises.map((p) => {
      if (p.status === "fulfilled") return p.value.results;

      return null;
    }) as any as ({ [k: string]: any }[] | null)[],
    permissions: currentUser.permissions as number,
  };
}

export default function () {
  const data: {
    etData: { [k: string]: any } | null;
    items: ({ [k: string]: any }[] | null)[];
    permissions: number;
  } = useLoaderData<typeof loader>();
  const timeStates: {
    [k: number]: { data: string; set: Dispatch<SetStateAction<string>> };
  } = {};
  const toast = useToast();

  for (const result of data.items) {
    if (!result) continue;

    for (const row of result) {
      const [data, set] = useState(new Date(row.created_at).toUTCString());
      timeStates[row.created_at] = {
        data,
        set,
      };

      useEffect(() => {
        timeStates[row.created_at].set(
          new Date(row.created_at).toLocaleString(),
        );
      }, [row.created_at]);
    }
  }

  async function fetchItem(id: string, type: string) {
    const itemResp = await fetch(`/api/me/items/${type}/${id}`);

    if (!itemResp.ok) {
      let error: string;

      try {
        error = ((await itemResp.json()) as { error: string }).error;
      } catch {
        error = "Unknown error";
      }

      toast({
        description: error,
        isClosable: true,
        status: "error",
        title: "Oops",
      });

      return;
    }

    const data: { [k: string]: any } = await itemResp.json();

    switch (type) {
      case "appeal":
        setModalBody(
          <ModalContent>
            <ModalHeader>View Appeal</ModalHeader>
            <ModalCloseButton />
            <ModalBody>
              <Heading size="lg">Why were you banned?</Heading>
              <br />
              <Text>
                <i>{data.ban_reason}</i>
              </Text>
              <br />
              <Divider />
              <br />
              <Heading size="lg">Why should we unban you?</Heading>
              <br />
              <Text>
                <i>{data.reason_for_unban}</i>
              </Text>
              <br />
              <Divider />
              <br />
              <Heading size="lg">
                What have you learned from your mistake?
              </Heading>
              <br />
              <Text>
                <i>{data.learned}</i>
              </Text>
            </ModalBody>
          </ModalContent>,
        );

        break;

      case "inactivity":
        setModalBody(
          <ModalContent>
            <ModalHeader>View Inactivity Notice</ModalHeader>
            <ModalCloseButton />
            <ModalBody>
              <Heading size="lg">Reason for Inactivity</Heading>
              <br />
              <Text>
                <i>{data.reason}</i>
              </Text>
              <br />
              <Divider />
              <br />
              <Heading size="lg">Start Date</Heading>
              <br />
              <Text>
                <i>{new Date(data.start).toLocaleDateString()}</i>
              </Text>
              <br />
              <Divider />
              <br />
              <Heading size="lg">End Date</Heading>
              <br />
              <Text>
                <i>{new Date(data.end).toLocaleDateString()}</i>
              </Text>
              <br />
              <Heading size="lg">Decisions</Heading>
              <br />
              <UnorderedList>
                {data.departments.map((d: string) => {
                  const dept = d as "DM" | "ET" | "FM" | "WM";

                  return (
                    <ListItem>
                      <Stack alignItems="center" direction="row">
                        <Text>{d}:&nbsp;</Text>
                        {typeof data.decisions[dept] === "boolean" ? (
                          data.decisions[dept] ? (
                            <svg
                              fill="currentColor"
                              height="16"
                              viewBox="0 0 16 16"
                              width="16"
                            >
                              <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z" />
                            </svg>
                          ) : (
                            <svg
                              fill="currentColor"
                              height="16"
                              viewBox="0 0 16 16"
                              width="16"
                            >
                              <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z" />
                            </svg>
                          )
                        ) : (
                          <svg
                            xmlns="http://www.w3.org/2000/svg"
                            width="16"
                            height="16"
                            fill="currentColor"
                            viewBox="0 0 16 16"
                          >
                            <path d="M2.5 15a.5.5 0 1 1 0-1h1v-1a4.5 4.5 0 0 1 2.557-4.06c.29-.139.443-.377.443-.59v-.7c0-.213-.154-.451-.443-.59A4.5 4.5 0 0 1 3.5 3V2h-1a.5.5 0 0 1 0-1h11a.5.5 0 0 1 0 1h-1v1a4.5 4.5 0 0 1-2.557 4.06c-.29.139-.443.377-.443.59v.7c0 .213.154.451.443.59A4.5 4.5 0 0 1 12.5 13v1h1a.5.5 0 0 1 0 1zm2-13v1c0 .537.12 1.045.337 1.5h6.326c.216-.455.337-.963.337-1.5V2zm3 6.35c0 .701-.478 1.236-1.011 1.492A3.5 3.5 0 0 0 4.5 13s.866-1.299 3-1.48zm1 0v3.17c2.134.181 3 1.48 3 1.48a3.5 3.5 0 0 0-1.989-3.158C8.978 9.586 8.5 9.052 8.5 8.351z" />
                          </svg>
                        )}
                      </Stack>
                    </ListItem>
                  );
                })}
              </UnorderedList>
            </ModalBody>
          </ModalContent>,
        );

        break;

      case "report":
        setModalBody(
          <ModalContent>
            <ModalHeader>View Report</ModalHeader>
            <ModalCloseButton />
            <ModalBody>
              <Heading size="lg">Username(s)</Heading>
              <br />
              <Text>
                <i>{data.target_usernames.toString()}</i>
              </Text>
              <br />
              <Divider />
              <br />
              <Heading size="lg">Description</Heading>
              <br />
              <Text>
                <i>{data.description ?? "No description"}</i>
              </Text>
              <br />
              <Divider />
              <br />
              <Heading size="lg">Media Links</Heading>
              <br />
              {data.resolved_attachments.map((attachment: string) => (
                <Link color="#646cff" href={attachment} target="_blank">
                  View media here
                </Link>
              ))}
            </ModalBody>
          </ModalContent>,
        );

        break;

      default:
        setModalBody(<ModalContent></ModalContent>);

        break;
    }

    onOpen();
  }

  const { isOpen, onClose, onOpen } = useDisclosure();
  const [modalBody, setModalBody] = useState(<ModalContent></ModalContent>);

  function resetModal() {
    onClose();
    setModalBody(<ModalContent></ModalContent>);
  }

  return (
    <Container maxW="container.lg">
      <Modal isCentered isOpen={isOpen} onClose={resetModal} size="lg">
        <ModalOverlay />
        {modalBody}
      </Modal>
      <Heading mb={8}>My Data</Heading>
      <br />
      <br />
      {data.permissions & (1 << 3) ? (
        <>
          <Heading size="lg">Events Team Info</Heading>
          <TableContainer mb="16px">
            <Table variant="simple">
              <TableCaption>
                Reach out to ETM if this info is incorrect
              </TableCaption>
              <Thead>
                <Tr>
                  <Th>Name</Th>
                  <Th>Points</Th>
                  <Th>Roblox ID</Th>
                </Tr>
              </Thead>
              <Tbody>
                <Tr>
                  <Td>{data.etData?.name}</Td>
                  <Td>{data.etData?.points}</Td>
                  <Td>
                    <Link
                      href={`https://www.roblox.com/users/${data.etData?.roblox_id}`}
                    >
                      {data.etData?.roblox_id}
                    </Link>
                  </Td>
                </Tr>
              </Tbody>
            </Table>
          </TableContainer>
        </>
      ) : null}
      <Heading size="lg">Discord Appeals</Heading>
      <TableContainer mb="16px">
        <Table variant="simple">
          <Thead>
            <Tr>
              <Th>Date</Th>
              <Th>ID</Th>
              <Th>Status</Th>
              <Th>View</Th>
            </Tr>
          </Thead>
          <Tbody>
            {data.items[0]?.map((result) => {
              return (
                <Tr>
                  <Td>{timeStates[result.created_at].data}</Td>
                  <Td>{result.id}</Td>
                  <Td>
                    {result.open
                      ? "Pending"
                      : typeof result.approved === "number"
                        ? `${result.approved ? "Accepted" : "Denied"}`
                        : "Unknown"}
                  </Td>
                  <Td>
                    <Button
                      onClick={async () => await fetchItem(result.id, "appeal")}
                    >
                      View
                    </Button>
                  </Td>
                </Tr>
              );
            })}
          </Tbody>
        </Table>
      </TableContainer>
      <br />
      {[1 << 2, 1 << 3, 1 << 9, 1 << 10].find((p) => data.permissions & p) ? (
        <>
          <Heading size="lg">Inactivity Notices</Heading>
          <TableContainer mb="16px">
            <Table variant="simple">
              <Thead>
                <Tr>
                  <Th>Date</Th>
                  <Th>ID</Th>
                  <Th>Status</Th>
                  <Th>View</Th>
                </Tr>
              </Thead>
              <Tbody>
                {data.items[1]?.map((result) => {
                  return (
                    <Tr>
                      <Td>{timeStates[result.created_at].data}</Td>
                      <Td>{result.id}</Td>
                      <Td>Open for details</Td>
                      <Td>
                        <Button
                          onClick={async () =>
                            await fetchItem(result.id, "inactivity")
                          }
                        >
                          View
                        </Button>
                      </Td>
                    </Tr>
                  );
                })}
              </Tbody>
            </Table>
          </TableContainer>
          <br />
        </>
      ) : null}
      <Heading size="lg">Reports</Heading>
      <TableContainer>
        <Table variant="simple">
          <Thead>
            <Tr>
              <Th>Date</Th>
              <Th>ID</Th>
              <Th>Status</Th>
              <Th>View</Th>
            </Tr>
          </Thead>
          <Tbody>
            {data.items[2]?.map((result) => {
              return (
                <Tr>
                  <Td>{timeStates[result.created_at].data}</Td>
                  <Td>{result.id}</Td>
                  <Td>{result.open ? "Pending" : "Reviewed"}</Td>
                  <Td>
                    <Button
                      onClick={async () => await fetchItem(result.id, "report")}
                    >
                      View
                    </Button>
                  </Td>
                </Tr>
              );
            })}
          </Tbody>
        </Table>
      </TableContainer>
    </Container>
  );
}