import {
  Box,
  Button,
  Card,
  CardBody,
  CardFooter,
  CardHeader,
  Container,
  Flex,
  Heading,
  HStack,
  Image,
  Input,
  InputGroup,
  InputRightElement,
  Link,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalFooter,
  ModalHeader,
  ModalOverlay,
  Spacer,
  Stack,
  StackDivider,
  Text,
  useDisclosure,
  useToast,
} from "@chakra-ui/react";
import { type FormEvent, type ReactElement, useState } from "react";

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

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

  if (
    !(currentUser.permissions & (1 << 5)) &&
    !(currentUser.permissions & (1 << 8))
  )
    throw new Response(null, {
      status: 403,
    });

  return null;
}

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

export default function () {
  const [queriedUsername, setQueriedUsername] = useState("");
  const [username, setUsername] = useState("");
  const [uid, setUid] = useState("");
  const [status, setStatus] = useState("");
  const [visible, setVisible] = useState(false);
  const [avatarUrl, setAvatarUrl] = useState("");
  const [ticketLink, setTicketLink] = useState("");
  const [history, setHistory] = useState([] as ReactElement[]);
  const [saveData, setSaveData] = useState({} as { [k: string]: any });
  const [loading, setLoading] = useState(false);
  const { isOpen, onClose, onOpen } = useDisclosure();
  const toast = useToast();
  const ticketRegex = /https:\/\/carcrushers\.modmail\.dev\/logs\/[a-f\d]{12}$/;

  async function getHistory() {
    setVisible(false);
    setLoading(true);
    setHistory([]);

    if (queriedUsername.length < 4) {
      setLoading(false);
      return toast({
        title: "Validation Error",
        description: `Username is too short`,
        status: "error",
      });
    }

    const historyResp = await fetch(
      `/api/game-bans/${queriedUsername}/history`,
    );

    if (!historyResp.ok) {
      setLoading(false);
      return toast({
        title: "Failed To Fetch User",
        description: `${
          ((await historyResp.json()) as { error: string }).error
        }`,
        status: "error",
      });
    }

    const {
      history,
      user,
    }: {
      history: { [k: string]: any }[];
      user: {
        avatar: string | null;
        current_status: string;
        id: number;
        name: string;
      };
    } = await historyResp.json();

    setAvatarUrl(user.avatar ?? "https://i.hep.gg/floppa");
    setUid(user.id.toString());
    setUsername(user.name);
    setStatus(user.current_status);

    const cardList = [];

    for (const entry of history) {
      const url = entry.evidence;
      const isUrl = () => {
        try {
          new URL(url).href;
          return true;
        } catch {
          return false;
        }
      };

      cardList.push(
        <Container mb={3}>
          <Card>
            <CardHeader>
              <Heading size="md">
                {new Date(entry.executed_at).toLocaleString()}
              </Heading>
            </CardHeader>
            <CardBody>
              <Stack divider={<StackDivider />} spacing="4">
                <Box>
                  <Heading size="xs">ACTION</Heading>
                  <Text pt="2" size="sm">
                    {entry.action}
                  </Text>
                </Box>
                <Box>
                  <Heading size="xs">EVIDENCE</Heading>
                  <Text pt="2" size="sm">
                    {isUrl() ? (
                      <Link color="#646cff" href={url}>
                        {url}
                      </Link>
                    ) : (
                      url
                    )}
                  </Text>
                </Box>
              </Stack>
            </CardBody>
          </Card>
        </Container>,
      );
    }

    setHistory(cardList);
    setLoading(false);
    setVisible(true);
  }

  async function getSaveData() {
    const dataResp = await fetch(`/api/game-bans/${uid}/save-data`);

    if (!dataResp.ok) {
      let msg = "Unknown error";

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

      toast({
        description: msg,
        status: "error",
        title: "Failed to get save data",
      });

      return;
    }

    setSaveData(await dataResp.json());
  }

  const invalidIcon = (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="16"
      height="16"
      fill="currentColor"
      viewBox="0 0 16 16"
      color="red"
    >
      <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" />
    </svg>
  );

  const validIcon = (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="16"
      height="16"
      fill="currentColor"
      viewBox="0 0 16 16"
      color="green"
    >
      <path d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.267.267 0 0 1 .02-.022z" />
    </svg>
  );

  async function revokePunishment() {
    const revokeResponse = await fetch(`/api/game-bans/${uid}/revoke`, {
      body: JSON.stringify({ ticket_link: ticketLink }),
      headers: {
        "content-type": "application/json",
      },
      method: "POST",
    });

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

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

      toast({
        description: error,
        isClosable: true,
        status: "error",
        title: "Oops",
      });
    } else {
      toast({
        description: `Punishment revoked for ${username}`,
        isClosable: true,
        status: "success",
        title: "Success",
      });
    }

    onClose();
    setTicketLink("");
  }

  return (
    <Container maxW="container.md">
      <Modal isCentered isOpen={isOpen} onClose={onClose} size="lg">
        <ModalOverlay />
        <ModalContent>
          <ModalHeader>Revoke punishment for {username}</ModalHeader>
          <ModalCloseButton />
          <ModalBody>
            <InputGroup>
              <Input
                onChange={(e) => setTicketLink(e.target.value)}
                placeholder="https://carcrushers.modmail.dev/logs/abcdef123456"
                maxLength={49}
              />
              <InputRightElement>
                {ticketLink.match(ticketRegex) ? validIcon : invalidIcon}
              </InputRightElement>
            </InputGroup>
          </ModalBody>
          <ModalFooter>
            <Button
              onClick={() => {
                onClose();
                setTicketLink("");
              }}
            >
              Cancel
            </Button>
            <Button
              colorScheme="red"
              disabled={!Boolean(ticketLink.match(ticketRegex))}
              ml="8px"
              onClick={async () => await revokePunishment()}
            >
              Revoke
            </Button>
          </ModalFooter>
        </ModalContent>
      </Modal>
      <Heading>User Lookup</Heading>
      <Text>Look up a user's punishment history here.</Text>
      <HStack mt={5}>
        <Input
          id="username"
          onBeforeInput={(e) => {
            const { data }: { data?: string } & FormEvent<HTMLInputElement> = e;

            if (data?.match(/\W/)) e.preventDefault();
          }}
          onChange={(e) => setQueriedUsername(e.target.value)}
          placeholder="Roblox username"
        />
        <Button
          ml="8px"
          onClick={async () => await getHistory()}
          isLoading={loading}
        >
          Search
        </Button>
      </HStack>
      <Container my={3}>
        <Card visibility={visible ? "visible" : "hidden"}>
          <CardBody>
            <Flex flexWrap="wrap" justifyContent="center">
              <Image mb="16" src={avatarUrl} />
              <Spacer />
              <Button
                colorScheme="red"
                onClick={onOpen}
                visibility={
                  status === "Not Moderated" || !status ? "hidden" : "visible"
                }
              >
                Revoke Punishment
              </Button>
            </Flex>
            <Stack divider={<StackDivider />} mt="8px" spacing="6">
              <Box>
                <Heading size="xs">USERNAME</Heading>
                <Text pt="2" fontSize="sm">
                  {username}
                </Text>
              </Box>
              <Box>
                <Heading size="xs">USER ID</Heading>
                <Text pt="2" fontSize="sm">
                  {uid}
                </Text>
              </Box>
              <Box>
                <Heading size="xs">MODERATION STATUS</Heading>
                <Text pt="2" fontSize="sm">
                  {status}
                </Text>
              </Box>
            </Stack>
          </CardBody>
          <CardFooter alignItems="center">
            <Link onClick={async () => await getSaveData()}>
              Click to Display Save Data
            </Link>
          </CardFooter>
        </Card>
      </Container>
      <Container
        display={Object.values(saveData).length ? undefined : "none"}
        my="16px"
      >
        <Card>
          <CardBody>
            <Stack divider={<StackDivider />} mt="8px" spacing="6">
              <Box>
                <Heading size="xs">Money</Heading>
                <Text pt="2" fontSize="sm">
                  {saveData.Money}
                </Text>
              </Box>
              <Box>
                <Heading size="xs">Parts</Heading>
                <Text pt="2" fontSize="sm">
                  {saveData.Parts}
                </Text>
              </Box>
              <Box>
                <Heading size="xs">Wins</Heading>
                <Text pt="2" fontSize="sm">
                  {saveData.Wins}
                </Text>
              </Box>
            </Stack>
          </CardBody>
        </Card>
      </Container>
      {history}
    </Container>
  );
}
