import {
  ActionIcon,
  Alert,
  Badge,
  Box,
  Card,
  Group,
  ScrollArea,
  Text,
  Tooltip,
} from "@mantine/core";
import {
  IconArrowsMaximize,
  IconArrowsMinimize,
  IconHandStop,
  IconInfoCircle,
  IconRefresh,
  IconVolume2,
} from "@tabler/icons-react";
import type { PublishFunction } from "create-pubsub";
import { usePubSub } from "create-pubsub/react";
import { lazy, type ReactNode, Suspense, useMemo, useState } from "react";
import { addLogEntry } from "../../modules/logEntries";
import { settingsPubSub } from "../../modules/pubSub";
import { searchAndRespond } from "../../modules/textGeneration";

const FormattedMarkdown = lazy(() => import("./FormattedMarkdown"));
const CopyIconButton = lazy(() => import("./CopyIconButton"));

export default function AiResponseContent({
  textGenerationState,
  response,
  setTextGenerationState,
}: {
  textGenerationState: string;
  response: string;
  setTextGenerationState: PublishFunction<
    | "failed"
    | "awaitingSearchResults"
    | "preparingToGenerate"
    | "idle"
    | "loadingModel"
    | "generating"
    | "interrupted"
    | "completed"
  >;
}) {
  const [settings, setSettings] = usePubSub(settingsPubSub);
  const [isSpeaking, setIsSpeaking] = useState(false);

  const ConditionalScrollArea = useMemo(
    () =>
      ({ children }: { children: ReactNode }) => {
        return settings.enableAiResponseScrolling ? (
          <ScrollArea.Autosize mah={300} type="auto" offsetScrollbars>
            {children}
          </ScrollArea.Autosize>
        ) : (
          <Box>{children}</Box>
        );
      },
    [settings.enableAiResponseScrolling],
  );

  function speakResponse(text: string) {
    if (isSpeaking) {
      self.speechSynthesis.cancel();
      setIsSpeaking(false);
      return;
    }

    const prepareTextForSpeech = (textToClean: string) => {
      const withoutReasoning = textToClean.replace(
        new RegExp(
          `${settings.reasoningStartMarker}[\\s\\S]*?${settings.reasoningEndMarker}`,
          "g",
        ),
        "",
      );
      const withoutLinks = withoutReasoning.replace(
        /\[([^\]]+)\]\([^)]+\)/g,
        "($1)",
      );
      const withoutMarkdown = withoutLinks.replace(/[#*`_~[\]]/g, "");
      return withoutMarkdown.trim();
    };

    const utterance = new SpeechSynthesisUtterance(prepareTextForSpeech(text));

    const voices = self.speechSynthesis.getVoices();

    if (voices.length > 0 && settings.selectedVoiceId) {
      const voice = voices.find(
        (voice) => voice.voiceURI === settings.selectedVoiceId,
      );

      if (voice) {
        utterance.voice = voice;
        utterance.lang = voice.lang;
      }
    }

    utterance.onerror = () => {
      addLogEntry("Failed to speak response");
      setIsSpeaking(false);
    };

    utterance.onend = () => setIsSpeaking(false);

    setIsSpeaking(true);
    self.speechSynthesis.speak(utterance);
  }

  return (
    <Card withBorder shadow="sm" radius="md">
      <Card.Section withBorder inheritPadding py="xs">
        <Group justify="space-between">
          <Group gap="xs" align="center">
            <Text fw={500}>
              {textGenerationState === "generating"
                ? "Generating AI Response..."
                : "AI Response"}
            </Text>
            {textGenerationState === "interrupted" && (
              <Badge variant="light" color="yellow" size="xs">
                Interrupted
              </Badge>
            )}
          </Group>
          <Group gap="xs" align="center">
            {textGenerationState === "generating" ? (
              <Tooltip label="Interrupt generation">
                <ActionIcon
                  onClick={() => setTextGenerationState("interrupted")}
                  variant="subtle"
                  color="gray"
                >
                  <IconHandStop size={16} />
                </ActionIcon>
              </Tooltip>
            ) : (
              <Tooltip label="Regenerate response">
                <ActionIcon
                  onClick={() => searchAndRespond()}
                  variant="subtle"
                  color="gray"
                >
                  <IconRefresh size={16} />
                </ActionIcon>
              </Tooltip>
            )}
            <Tooltip
              label={isSpeaking ? "Stop speaking" : "Listen to response"}
            >
              <ActionIcon
                onClick={() => speakResponse(response)}
                variant="subtle"
                color={isSpeaking ? "blue" : "gray"}
              >
                <IconVolume2 size={16} />
              </ActionIcon>
            </Tooltip>
            {settings.enableAiResponseScrolling ? (
              <Tooltip label="Show full response without scroll bar">
                <ActionIcon
                  onClick={() => {
                    setSettings({
                      ...settings,
                      enableAiResponseScrolling: false,
                    });
                  }}
                  variant="subtle"
                  color="gray"
                >
                  <IconArrowsMaximize size={16} />
                </ActionIcon>
              </Tooltip>
            ) : (
              <Tooltip label="Enable scroll bar">
                <ActionIcon
                  onClick={() => {
                    setSettings({
                      ...settings,
                      enableAiResponseScrolling: true,
                    });
                  }}
                  variant="subtle"
                  color="gray"
                >
                  <IconArrowsMinimize size={16} />
                </ActionIcon>
              </Tooltip>
            )}
            <Suspense>
              <CopyIconButton value={response} tooltipLabel="Copy response" />
            </Suspense>
          </Group>
        </Group>
      </Card.Section>
      <Card.Section withBorder>
        <ConditionalScrollArea>
          <Suspense>
            <FormattedMarkdown>{response}</FormattedMarkdown>
          </Suspense>
        </ConditionalScrollArea>
        {textGenerationState === "failed" && (
          <Alert
            variant="light"
            color="yellow"
            title="Failed to generate response"
            icon={<IconInfoCircle />}
          >
            Could not generate response. Please try refreshing the page.
          </Alert>
        )}
      </Card.Section>
    </Card>
  );
}
