"use client";

import "../../widgets-common.css";

import { useState } from "react";
import {
  ActionIcon,
  Badge,
  Button,
  Card,
  Flex,
  Image,
  ScrollArea,
  Stack,
  Text,
  Tooltip,
  UnstyledButton,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { IconCircleFilled, IconClockPause, IconPlayerPlay, IconPlayerStop } from "@tabler/icons-react";
import dayjs from "dayjs";

import type { RouterOutputs } from "@homarr/api";
import { clientApi } from "@homarr/api/client";
import { useIntegrationsWithInteractAccess } from "@homarr/auth/client";
import { integrationDefs } from "@homarr/definitions";
import type { TranslationFunction } from "@homarr/translation";
import { useI18n } from "@homarr/translation/client";

import { widgetKind } from ".";
import type { WidgetComponentProps } from "../../definition";
import { NoIntegrationSelectedError } from "../../errors";
import TimerModal from "./TimerModal";

const dnsLightStatus = (enabled: boolean | undefined) =>
  `var(--mantine-color-${typeof enabled === "undefined" ? "blue" : enabled ? "green" : "red"}-6`;

export default function DnsHoleControlsWidget({
  options,
  integrationIds,
  isEditMode,
  serverData,
}: WidgetComponentProps<typeof widgetKind>) {
  // DnsHole integrations with interaction permissions
  const integrationsWithInteractions = useIntegrationsWithInteractAccess()
    .map(({ id }) => id)
    .filter((id) => integrationIds.includes(id));

  // Initial summaries, null summary means disconnected, undefined status means processing
  const [summaries, setSummaries] = useState(serverData?.initialData ?? []);

  // Subscribe to summary updates
  clientApi.widget.dnsHole.subscribeToSummary.useSubscription(
    {
      widgetKind,
      integrationIds,
    },
    {
      onData: (data) => {
        setSummaries((prevSummaries) =>
          prevSummaries.map((summary) => (summary.integration.id === data.integration.id ? data : summary)),
        );
      },
    },
  );

  // Mutations for dnsHole state, set to undefined on click, and change again on settle
  const { mutate: enableDns } = clientApi.widget.dnsHole.enable.useMutation({
    onSettled: (_, error, { integrationId }) => {
      setSummaries((prevSummaries) =>
        prevSummaries.map((data) => ({
          ...data,
          summary:
            data.integration.id === integrationId && data.summary
              ? { ...data.summary, status: error ? "disabled" : "enabled" }
              : data.summary,
        })),
      );
    },
  });
  const { mutate: disableDns } = clientApi.widget.dnsHole.disable.useMutation({
    onSettled: (_, error, { integrationId }) => {
      setSummaries((prevSummaries) =>
        prevSummaries.map((data) => ({
          ...data,
          summary:
            data.integration.id === integrationId && data.summary
              ? { ...data.summary, status: error ? "enabled" : "disabled" }
              : data.summary,
        })),
      );
    },
  });
  const toggleDns = (integrationId: string) => {
    const integrationStatus = summaries.find(({ integration }) => integration.id === integrationId);
    if (!integrationStatus?.summary?.status) return;
    setSummaries((prevSummaries) =>
      prevSummaries.map((data) => ({
        ...data,
        summary:
          data.integration.id === integrationId && data.summary ? { ...data.summary, status: undefined } : data.summary,
      })),
    );
    if (integrationStatus.summary.status === "enabled") {
      disableDns({ integrationId, duration: 0 });
    } else {
      enableDns({ integrationId });
    }
  };

  // make lists of enabled and disabled interactable integrations (with permissions, not disconnected and not processing)
  const integrationsSummaries = summaries.reduce(
    (acc, { summary, integration: { id } }) =>
      integrationsWithInteractions.includes(id) && summary?.status != null ? (acc[summary.status].push(id), acc) : acc,
    { enabled: [] as string[], disabled: [] as string[] },
  );

  const t = useI18n();

  // Timer modal setup
  const [selectedIntegrationIds, setSelectedIntegrationIds] = useState<string[]>([]);
  const [opened, { close, open }] = useDisclosure(false);

  const controlAllButtonsVisible = options.showToggleAllButtons && integrationsWithInteractions.length > 0;

  if (integrationIds.length === 0) {
    throw new NoIntegrationSelectedError();
  }

  return (
    <Flex
      className="dns-hole-controls-stack"
      h="100%"
      direction="column"
      p="2.5cqmin"
      gap="2.5cqmin"
      style={{ pointerEvents: isEditMode ? "none" : undefined }}
    >
      {controlAllButtonsVisible && (
        <Flex className="dns-hole-controls-buttons" gap="2.5cqmin">
          <Tooltip label={t("widget.dnsHoleControls.controls.enableAll")}>
            <Button
              className="dns-hole-controls-enable-all-button"
              onClick={() => integrationsSummaries.disabled.forEach((integrationId) => toggleDns(integrationId))}
              disabled={integrationsSummaries.disabled.length === 0}
              variant="light"
              color="green"
              h="fit-content"
              p="1.25cqmin"
              bd={0}
              radius="2.5cqmin"
              flex={1}
            >
              <IconPlayerPlay
                className="dns-hole-controls-enable-all-icon"
                style={{ height: "7.5cqmin", width: "7.5cqmin" }}
              />
            </Button>
          </Tooltip>

          <Tooltip label={t("widget.dnsHoleControls.controls.setTimer")}>
            <Button
              className="dns-hole-controls-timer-all-button"
              onClick={() => {
                setSelectedIntegrationIds(integrationsSummaries.enabled);
                open();
              }}
              disabled={integrationsSummaries.enabled.length === 0}
              variant="light"
              color="yellow"
              h="fit-content"
              p="1.25cqmin"
              bd={0}
              radius="2.5cqmin"
              flex={1}
            >
              <IconClockPause
                className="dns-hole-controls-timer-all-icon"
                style={{ height: "7.5cqmin", width: "7.5cqmin" }}
              />
            </Button>
          </Tooltip>

          <Tooltip label={t("widget.dnsHoleControls.controls.disableAll")}>
            <Button
              className="dns-hole-controls-disable-all-button"
              onClick={() => integrationsSummaries.enabled.forEach((integrationId) => toggleDns(integrationId))}
              disabled={integrationsSummaries.enabled.length === 0}
              variant="light"
              color="red"
              h="fit-content"
              p="1.25cqmin"
              bd={0}
              radius="2.5cqmin"
              flex={1}
            >
              <IconPlayerStop
                className="dns-hole-controls-disable-all-icon"
                style={{ height: "7.5cqmin", width: "7.5cqmin" }}
              />
            </Button>
          </Tooltip>
        </Flex>
      )}

      <ScrollArea className="dns-hole-controls-integration-list-scroll-area flexed-scroll-area">
        <Stack
          className="dns-hole-controls-integration-list"
          gap="2.5cqmin"
          flex={1}
          justify={controlAllButtonsVisible ? "flex-end" : "space-evenly"}
        >
          {summaries.map((summary) => (
            <ControlsCard
              key={summary.integration.id}
              integrationsWithInteractions={integrationsWithInteractions}
              toggleDns={toggleDns}
              data={summary}
              setSelectedIntegrationIds={setSelectedIntegrationIds}
              open={open}
              t={t}
            />
          ))}
        </Stack>
      </ScrollArea>

      <TimerModal
        opened={opened}
        close={close}
        selectedIntegrationIds={selectedIntegrationIds}
        disableDns={disableDns}
      />
    </Flex>
  );
}

interface ControlsCardProps {
  integrationsWithInteractions: string[];
  toggleDns: (integrationId: string) => void;
  data: RouterOutputs["widget"]["dnsHole"]["summary"][number];
  setSelectedIntegrationIds: (integrationId: string[]) => void;
  open: () => void;
  t: TranslationFunction;
}

const ControlsCard: React.FC<ControlsCardProps> = ({
  integrationsWithInteractions,
  toggleDns,
  data,
  setSelectedIntegrationIds,
  open,
  t,
}) => {
  // Independently determine connection status, current state and permissions
  const isConnected = data.summary !== null && Math.abs(dayjs(data.timestamp).diff()) < 30000;
  const isEnabled = data.summary?.status ? data.summary.status === "enabled" : undefined;
  const isInteractPermitted = integrationsWithInteractions.includes(data.integration.id);
  // Use all factors to infer the state of the action buttons
  const controlEnabled = isInteractPermitted && isEnabled !== undefined && isConnected;

  return (
    <Card
      className={`dns-hole-controls-integration-item-outer-shell dns-hole-controls-integration-item-${data.integration.id} dns-hole-controls-integration-item-${data.integration.name}`}
      key={data.integration.id}
      withBorder
      p="2.5cqmin"
      radius="2.5cqmin"
    >
      <Flex className="dns-hole-controls-item-container" gap="4cqmin" align="center" direction="row">
        <Image
          className="dns-hole-controls-item-icon"
          src={integrationDefs[data.integration.kind].iconUrl}
          w="20cqmin"
          h="20cqmin"
          fit="contain"
          style={{ filter: !isConnected ? "grayscale(100%)" : undefined }}
        />
        <Flex className="dns-hole-controls-item-data-stack" direction="column" gap="1.5cqmin">
          <Text className="dns-hole-controls-item-integration-name" fz="7cqmin">
            {data.integration.name}
          </Text>
          <Flex className="dns-hole-controls-item-controls" direction="row" gap="1.5cqmin">
            <UnstyledButton
              className="dns-hole-controls-item-toggle-button"
              disabled={!controlEnabled}
              display="contents"
              style={{ cursor: controlEnabled ? "pointer" : "default" }}
              onClick={() => toggleDns(data.integration.id)}
            >
              <Badge
                className={`dns-hole-controls-item-toggle-button-styling${controlEnabled ? " hoverable-component clickable-component" : ""}`}
                bd="0.1cqmin solid var(--border-color)"
                px="2.5cqmin"
                h="7.5cqmin"
                fz="4.5cqmin"
                lts="0.1cqmin"
                color="var(--background-color)"
                c="var(--mantine-color-text)"
                styles={{ section: { marginInlineEnd: "2.5cqmin" } }}
                leftSection={
                  isConnected && (
                    <IconCircleFilled
                      className="dns-hole-controls-item-status-icon"
                      color={dnsLightStatus(isEnabled)}
                      style={{ height: "3.5cqmin", width: "3.5cqmin" }}
                    />
                  )
                }
              >
                {t(
                  `widget.dnsHoleControls.controls.${
                    !isConnected
                      ? "disconnected"
                      : typeof isEnabled === "undefined"
                        ? "processing"
                        : isEnabled
                          ? "enabled"
                          : "disabled"
                  }`,
                )}
              </Badge>
            </UnstyledButton>
            <ActionIcon
              className="dns-hole-controls-item-timer-button"
              display={isInteractPermitted ? undefined : "none"}
              disabled={!controlEnabled || !isEnabled}
              color="yellow"
              size="fit-content"
              radius="999px 999px 0px 999px"
              bd={0}
              variant="subtle"
              onClick={() => {
                setSelectedIntegrationIds([data.integration.id]);
                open();
              }}
            >
              <IconClockPause
                className="dns-hole-controls-item-timer-icon"
                style={{ height: "7.5cqmin", width: "7.5cqmin" }}
              />
            </ActionIcon>
          </Flex>
        </Flex>
      </Flex>
    </Card>
  );
};
