import {
  ActionIcon,
  Box,
  Button,
  Group,
  Modal,
  Text,
  TextInput,
} from "@mantine/core";
import { IconExternalLink } from "@tabler/icons-react";
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import CopyTextButton from "@/components/common/copy.tsx";
import { getAppUrl } from "@/lib/config.ts";
import {
  useRemoveShareAliasMutation,
  useSetShareAliasMutation,
  useShareAliasForPageQuery,
} from "@/features/share/queries/share-query.ts";
import { checkShareAliasAvailability } from "@/features/share/services/share-service.ts";
import {
  isValidShareAlias,
  normalizeShareAlias,
} from "@/features/share/share-alias.util.ts";

interface ShareAliasSectionProps {
  pageId: string;
  readOnly: boolean;
}

// The prefix label shown next to the slug input, e.g. "docs.example.com/l/".
function aliasPrefixLabel(): string {
  const url = getAppUrl();
  const host = url.replace(/^https?:\/\//, "").replace(/\/+$/, "");
  return `${host}/l/`;
}

export default function ShareAliasSection({
  pageId,
  readOnly,
}: ShareAliasSectionProps) {
  const { t } = useTranslation();
  const { data: currentAlias } = useShareAliasForPageQuery(pageId);
  const setAliasMutation = useSetShareAliasMutation();
  const removeAliasMutation = useRemoveShareAliasMutation();

  const [value, setValue] = useState("");
  const [availability, setAvailability] = useState<{
    valid: boolean;
    available: boolean;
    currentPageId: string | null;
  } | null>(null);
  const [reassign, setReassign] = useState<{
    alias: string;
    currentPageTitle: string | null;
  } | null>(null);

  // Seed the input from the page's current alias (if any).
  useEffect(() => {
    setValue(currentAlias?.alias ?? "");
  }, [currentAlias?.alias, pageId]);

  const normalized = useMemo(() => normalizeShareAlias(value), [value]);
  const isValid = isValidShareAlias(normalized);
  const unchanged = currentAlias?.alias === normalized;

  // Debounced availability probe (skips when invalid or unchanged).
  const debounceRef = useRef<ReturnType<typeof setTimeout>>();
  useEffect(() => {
    setAvailability(null);
    if (!isValid || unchanged) return;
    debounceRef.current && clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(async () => {
      try {
        const res = await checkShareAliasAvailability(normalized);
        setAvailability({
          valid: res.valid,
          available: res.available,
          currentPageId: res.currentPageId,
        });
      } catch {
        setAvailability(null);
      }
    }, 400);
    return () => {
      debounceRef.current && clearTimeout(debounceRef.current);
    };
  }, [normalized, isValid, unchanged]);

  const prettyLink = currentAlias?.alias
    ? `${getAppUrl()}/l/${currentAlias.alias}`
    : null;

  const handleSave = async (confirmReassign = false) => {
    try {
      await setAliasMutation.mutateAsync({
        pageId,
        alias: normalized,
        confirmReassign,
      });
      setReassign(null);
    } catch (error: any) {
      // The address already points at another page: prompt to move it here.
      if (error?.status === 409 || error?.response?.status === 409) {
        const data = error?.response?.data;
        if (data?.code === "ALIAS_REASSIGN_REQUIRED") {
          setReassign({
            alias: normalized,
            currentPageTitle: data?.currentPageTitle ?? null,
          });
        }
      }
    }
  };

  const handleRemove = async () => {
    if (!currentAlias?.id) return;
    await removeAliasMutation.mutateAsync(currentAlias.id);
    setValue("");
  };

  const showInvalid = normalized.length > 0 && !isValid;
  // The typed name is already in use by ANOTHER page. This is NOT a dead end:
  // hitting Save triggers the server's 409 `ALIAS_REASSIGN_REQUIRED` and opens
  // the "Move custom address?" confirm modal that retargets the address here.
  // So surface it as an informational hint (not a terminal red error) and keep
  // Save enabled, instead of looking like the address is unusable.
  const reassignable =
    isValid && !unchanged && !!availability && !availability.available;

  // The slug prefix (e.g. "docs.example.com/l/") is static for the session.
  const prefixLabel = aliasPrefixLabel();
  const prefixRef = useRef<HTMLDivElement>(null);
  const [prefixWidth, setPrefixWidth] = useState(0);

  // Measure the real rendered width of the prefix so the slug input sits flush
  // next to it, instead of after an over-estimated character-counted gap.
  useLayoutEffect(() => {
    if (prefixRef.current) {
      setPrefixWidth(Math.ceil(prefixRef.current.scrollWidth) + 1);
    }
  }, [prefixLabel]);

  return (
    <>
      <Text size="sm" fw={500} mt="md">
        {t("Custom address")}
      </Text>
      <Text size="xs" c="dimmed" mb={6}>
        {t("A short, memorable link you can point at any shared page.")}
      </Text>

      {prettyLink && (
        <Group my="xs" gap={4} wrap="nowrap">
          <TextInput
            variant="filled"
            value={prettyLink}
            readOnly
            rightSection={<CopyTextButton text={prettyLink} />}
            style={{ width: "100%" }}
          />
          <ActionIcon
            component="a"
            variant="default"
            target="_blank"
            href={prettyLink}
            size="sm"
          >
            <IconExternalLink size={16} />
          </ActionIcon>
        </Group>
      )}

      <TextInput
        value={value}
        onChange={(e) => setValue(e.currentTarget.value)}
        // Show the canonical form once the user pauses so what they type maps
        // visibly to what gets stored.
        onBlur={() => setValue(normalized)}
        leftSection={
          <Box
            ref={prefixRef}
            style={{
              display: "flex",
              alignItems: "center",
              width: "100%",
              height: "100%",
              paddingInline: "var(--mantine-spacing-xs)",
              whiteSpace: "nowrap",
              fontSize: "var(--mantine-font-size-xs)",
              color: "var(--mantine-color-dimmed)",
              backgroundColor: "var(--mantine-color-default-hover)",
              borderTopLeftRadius: "var(--input-radius)",
              borderBottomLeftRadius: "var(--input-radius)",
            }}
          >
            {prefixLabel}
          </Box>
        }
        leftSectionWidth={prefixWidth || undefined}
        placeholder={t("my-page")}
        disabled={readOnly}
        error={
          showInvalid
            ? t("Use 2-60 lowercase letters, digits and hyphens")
            : undefined
        }
        description={
          reassignable
            ? t("This address is in use. Saving will move it to this page.")
            : undefined
        }
      />

      <Group mt="sm" gap="xs">
        <Button
          size="compact-sm"
          onClick={() => handleSave(false)}
          loading={setAliasMutation.isPending}
          disabled={readOnly || !isValid || unchanged}
        >
          {t("Save")}
        </Button>
        {currentAlias?.id && (
          <Button
            size="compact-sm"
            variant="default"
            color="red"
            onClick={handleRemove}
            loading={removeAliasMutation.isPending}
            disabled={readOnly}
          >
            {t("Remove")}
          </Button>
        )}
      </Group>

      <Modal
        opened={!!reassign}
        onClose={() => setReassign(null)}
        title={t("Move custom address?")}
        centered
        size="sm"
      >
        <Text size="sm">
          {reassign?.currentPageTitle
            ? t(
                'The address "{{alias}}" currently points to "{{title}}". Move it to this page?',
                {
                  alias: reassign?.alias,
                  title: reassign?.currentPageTitle,
                },
              )
            : t(
                'The address "{{alias}}" is already in use. Move it to this page?',
                { alias: reassign?.alias },
              )}
        </Text>
        <Group justify="flex-end" mt="md">
          <Button variant="default" onClick={() => setReassign(null)}>
            {t("Cancel")}
          </Button>
          <Button
            color="red"
            onClick={() => handleSave(true)}
            loading={setAliasMutation.isPending}
          >
            {t("Move here")}
          </Button>
        </Group>
      </Modal>
    </>
  );
}
