import {
  Button,
  Container,
  Divider,
  Heading,
  Link,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalHeader,
  ModalOverlay,
  Table,
  TableContainer,
  Tbody,
  Td,
  Text,
  Th,
  Thead,
  Tr,
  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 user = ?
         ORDER BY created_at DESC;`,
      )
        .bind(currentUser.id)
        .all(),
    );

  const settledPromises = await Promise.allSettled(d1Promises);

  return {
    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: {
    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>
            </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 />
      <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>
                        {result.open
                          ? "Pending"
                          : result.approved
                          ? "Approved"
                          : "Denied"}
                      </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>
  );
}