import { withModal } from "@/modules/modals";
import { task, TaskGroup } from "@/modules/task";
import { useTableStyles } from "@/styles";
import { BuildKey, GetItemId } from "@/utilities";
import {
  faCaretDown,
  faCheck,
  faCheckCircle,
  faDownload,
  faExclamationCircle,
  faInfoCircle,
  faTimes,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  Alert,
  Anchor,
  Badge,
  Button,
  Collapse,
  Divider,
  Group,
  List,
  Popover,
  Stack,
  Text,
} from "@mantine/core";
import { useHover } from "@mantine/hooks";
import { FunctionComponent, useCallback, useMemo, useState } from "react";
import { UseQueryResult } from "react-query";
import { Column } from "react-table";
import { Action, PageTable } from "..";
import Language from "../bazarr/Language";

type SupportType = Item.Movie | Item.Episode;

interface Props<T extends SupportType> {
  download: (item: T, result: SearchResultType) => Promise<void>;
  query: (
    id?: number
  ) => UseQueryResult<SearchResultType[] | undefined, unknown>;
  item: T;
}

function ManualSearchView<T extends SupportType>(props: Props<T>) {
  const { download, query: useSearch, item } = props;

  const itemId = useMemo(() => GetItemId(item ?? {}), [item]);

  const [id, setId] = useState<number | undefined>(undefined);

  const results = useSearch(id);

  const isStale = results.data === undefined;

  const search = useCallback(() => {
    setId(itemId);
    results.refetch();
  }, [itemId, results]);

  const columns = useMemo<Column<SearchResultType>[]>(
    () => [
      {
        Header: "Score",
        accessor: "score",
        Cell: ({ value }) => {
          const { classes } = useTableStyles();
          return <Text className={classes.noWrap}>{value}%</Text>;
        },
      },
      {
        accessor: "language",
        Cell: ({ row: { original }, value }) => {
          const lang: Language.Info = {
            code2: value,
            hi: original.hearing_impaired === "True",
            forced: original.forced === "True",
            name: "",
          };
          return (
            <Badge>
              <Language.Text value={lang}></Language.Text>
            </Badge>
          );
        },
      },
      {
        Header: "Provider",
        accessor: "provider",
        Cell: (row) => {
          const { classes } = useTableStyles();
          const value = row.value;
          const { url } = row.row.original;
          if (url) {
            return (
              <Anchor
                className={classes.noWrap}
                href={url}
                target="_blank"
                rel="noopener noreferrer"
              >
                {value}
              </Anchor>
            );
          } else {
            return value;
          }
        },
      },
      {
        Header: "Release",
        accessor: "release_info",
        Cell: ({ value }) => {
          const { classes } = useTableStyles();
          const [open, setOpen] = useState(false);

          const items = useMemo(
            () => value.slice(1).map((v, idx) => <Text key={idx}>{v}</Text>),
            [value]
          );

          if (value.length === 0) {
            return <Text color="dimmed">Cannot get release info</Text>;
          }

          return (
            <Stack spacing={0} onClick={() => setOpen((o) => !o)}>
              <Text className={classes.primary}>
                {value[0]}
                {value.length > 1 && (
                  <FontAwesomeIcon
                    icon={faCaretDown}
                    rotation={open ? 180 : undefined}
                  ></FontAwesomeIcon>
                )}
              </Text>
              <Collapse in={open}>
                <>{items}</>
              </Collapse>
            </Stack>
          );
        },
      },
      {
        Header: "Upload",
        accessor: "uploader",
        Cell: ({ value }) => {
          const { classes } = useTableStyles();
          return <Text className={classes.noWrap}>{value ?? "-"}</Text>;
        },
      },
      {
        accessor: "matches",
        Cell: (row) => {
          const { matches, dont_matches } = row.row.original;
          return <StateIcon matches={matches} dont={dont_matches}></StateIcon>;
        },
      },
      {
        accessor: "subtitle",
        Cell: ({ row }) => {
          const result = row.original;
          return (
            <Action
              icon={faDownload}
              color="brand"
              variant="light"
              disabled={item === null}
              onClick={() => {
                if (!item) return;

                task.create(
                  item.title,
                  TaskGroup.DownloadSubtitle,
                  download,
                  item,
                  result
                );
              }}
            ></Action>
          );
        },
      },
    ],
    [download, item]
  );

  return (
    <Stack>
      <Alert
        title="Resource"
        color="gray"
        icon={<FontAwesomeIcon icon={faInfoCircle}></FontAwesomeIcon>}
      >
        {item?.path}
      </Alert>
      <Collapse in={!isStale && !results.isFetching}>
        <PageTable
          tableStyles={{ emptyText: "No result", placeholder: 10 }}
          columns={columns}
          data={results.data ?? []}
        ></PageTable>
      </Collapse>
      <Divider></Divider>
      <Button loading={results.isFetching} fullWidth onClick={search}>
        {isStale ? "Search" : "Search Again"}
      </Button>
    </Stack>
  );
}

export const MovieSearchModal = withModal<Props<Item.Movie>>(
  ManualSearchView,
  "movie-manual-search",
  { title: "Search Subtitles", size: "xl" }
);
export const EpisodeSearchModal = withModal<Props<Item.Episode>>(
  ManualSearchView,
  "episode-manual-search",
  { title: "Search Subtitles", size: "xl" }
);

const StateIcon: FunctionComponent<{ matches: string[]; dont: string[] }> = ({
  matches,
  dont,
}) => {
  const hasIssues = dont.length > 0;

  const { ref, hovered } = useHover();

  return (
    <Popover
      opened={hovered}
      placement="center"
      position="top"
      target={
        <Text color={hasIssues ? "yellow" : "green"} ref={ref}>
          <FontAwesomeIcon
            icon={hasIssues ? faExclamationCircle : faCheckCircle}
          ></FontAwesomeIcon>
        </Text>
      }
    >
      <Group align="flex-start" spacing="xl">
        <Stack align="flex-start" spacing="xs">
          <Text color="green">
            <FontAwesomeIcon icon={faCheck}></FontAwesomeIcon>
          </Text>
          <List>
            {matches.map((v, idx) => (
              <List.Item key={BuildKey(idx, v, "match")}>{v}</List.Item>
            ))}
          </List>
        </Stack>
        <Stack align="flex-start" spacing="xs">
          <Text color="yellow">
            <FontAwesomeIcon icon={faTimes}></FontAwesomeIcon>
          </Text>
          <List>
            {dont.map((v, idx) => (
              <List.Item key={BuildKey(idx, v, "miss")}>{v}</List.Item>
            ))}
          </List>
        </Stack>
      </Group>
    </Popover>
  );
};
