import {
  ActionIcon,
  Badge,
  Box,
  Button,
  Group,
  Indicator,
  Loader,
  Popover,
  ScrollArea,
  Stack,
  Text,
  Tooltip,
  UnstyledButton,
} from "@mantine/core";
import { IconAt, IconBell, IconCheck, IconMessage, IconUserCheck } from "@tabler/icons-react";
import { ReactElement, useCallback, useEffect, useState } from "react";
import * as api from "../api";
import type { Notification, NotificationKind } from "../types";
import { formatDateTimeShort } from "./format";

interface Props {
  // External counter — App.tsx updates this via SSE events. When undefined
  // the bell polls /api/notifications/unread-count on mount.
  unreadCount?: number;
  notifications?: Notification[];
  // Called when the user clicks a notification → open the relevant card.
  // messageId points to the chat message that triggered the notification so
  // the parent can scroll to it.
  onOpenCard?: (cardId: string, messageId: string) => void;
  // Called whenever the bell mutates state (mark read / mark all) so the
  // parent can refresh its cached lists.
  onChanged?: () => void;
}

const kindIcon: Record<NotificationKind, ReactElement> = {
  mention: <IconAt size={14} />,
  assigned_chat: <IconUserCheck size={14} />,
  reply: <IconMessage size={14} />,
};

const kindLabel: Record<NotificationKind, string> = {
  mention: "Mencion",
  assigned_chat: "Asignado",
  reply: "Respuesta",
};

const kindColor: Record<NotificationKind, string> = {
  mention: "grape",
  assigned_chat: "blue",
  reply: "gray",
};

export function NotificationsBell({ unreadCount: extCount, notifications: extList, onOpenCard, onChanged }: Props) {
  const [opened, setOpened] = useState(false);
  const [items, setItems] = useState<Notification[]>(extList ?? []);
  const [count, setCount] = useState<number>(extCount ?? 0);
  const [loading, setLoading] = useState(false);

  // Keep local state in sync with parent-supplied values when present.
  useEffect(() => {
    if (extList) setItems(extList);
  }, [extList]);
  useEffect(() => {
    if (extCount !== undefined) setCount(extCount);
  }, [extCount]);

  const refresh = useCallback(async () => {
    setLoading(true);
    try {
      const [list, c] = await Promise.all([
        api.listNotifications(false),
        api.unreadNotificationCount(),
      ]);
      setItems(list);
      setCount(c.count);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    // Initial fetch only when parent does not provide list/count.
    if (extList === undefined || extCount === undefined) {
      refresh();
    }
  }, [extList, extCount, refresh]);

  const handleOpen = (isOpen: boolean) => {
    setOpened(isOpen);
    if (isOpen) refresh();
  };

  const handleClick = async (n: Notification) => {
    if (!n.read_at) {
      try {
        await api.markNotificationRead(n.id);
        setItems((prev) => prev.map((x) => (x.id === n.id ? { ...x, read_at: new Date().toISOString() } : x)));
        setCount((c) => Math.max(0, c - 1));
        onChanged?.();
      } catch {
        // ignore — UI will recover on next refresh
      }
    }
    setOpened(false);
    onOpenCard?.(n.card_id, n.message_id);
  };

  const handleMarkAll = async () => {
    try {
      await api.markAllNotificationsRead();
      setItems((prev) => prev.map((x) => (x.read_at ? x : { ...x, read_at: new Date().toISOString() })));
      setCount(0);
      onChanged?.();
    } catch {
      // ignore
    }
  };

  const badge = (
    <ActionIcon variant="subtle" aria-label="Notificaciones">
      <IconBell size={16} />
    </ActionIcon>
  );

  return (
    <Popover opened={opened} onChange={handleOpen} position="bottom-end" width={380} withArrow shadow="md">
      <Popover.Target>
        <Box onClick={() => handleOpen(!opened)} style={{ display: "inline-flex" }}>
          {count > 0 ? (
            <Indicator color="red" label={count > 99 ? "99+" : count} size={16} offset={4}>
              {badge}
            </Indicator>
          ) : (
            badge
          )}
        </Box>
      </Popover.Target>
      <Popover.Dropdown p={0}>
        <Group justify="space-between" px="sm" py="xs">
          <Text fw={600} size="sm">Notificaciones</Text>
          <Tooltip label="Marcar todas como leidas" withArrow>
            <Button
              size="compact-xs"
              variant="subtle"
              leftSection={<IconCheck size={12} />}
              onClick={handleMarkAll}
              disabled={count === 0}
            >
              Todas leidas
            </Button>
          </Tooltip>
        </Group>
        <ScrollArea h={420} type="auto" offsetScrollbars>
          {loading && items.length === 0 ? (
            <Group justify="center" p="md"><Loader size="sm" /></Group>
          ) : items.length === 0 ? (
            <Text size="sm" c="dimmed" ta="center" p="md">Sin notificaciones</Text>
          ) : (
            <Stack gap={0}>
              {items.map((n) => {
                const unread = !n.read_at;
                return (
                  <UnstyledButton
                    key={n.id}
                    onClick={() => handleClick(n)}
                    p="sm"
                    style={{
                      borderTop: "1px solid var(--mantine-color-gray-2)",
                      background: unread ? "var(--mantine-color-blue-light)" : undefined,
                      textAlign: "left",
                    }}
                  >
                    <Group gap={6} wrap="nowrap" align="flex-start">
                      <Badge size="xs" variant="light" color={kindColor[n.kind]} leftSection={kindIcon[n.kind]}>
                        {kindLabel[n.kind]}
                      </Badge>
                      <Box style={{ flex: 1, minWidth: 0 }}>
                        <Group gap={6} wrap="nowrap" justify="space-between">
                          <Text size="xs" fw={600} truncate>
                            {n.actor_name || "Alguien"} · #{n.card_seq_num} {n.card_title}
                          </Text>
                          <Text size="xs" c="dimmed">{formatDateTimeShort(n.created_at)}</Text>
                        </Group>
                        <Text size="xs" c={unread ? undefined : "dimmed"} lineClamp={2} style={{ whiteSpace: "pre-wrap" }}>
                          {n.snippet}
                        </Text>
                      </Box>
                    </Group>
                  </UnstyledButton>
                );
              })}
            </Stack>
          )}
        </ScrollArea>
      </Popover.Dropdown>
    </Popover>
  );
}
