import React, { useEffect, useState, useCallback, useRef } from "react";
import { Flex, Stack, Text, Title, Grid, Card, Group, Button, Table, Badge, ActionIcon, Pagination, Tooltip, Loader, TextInput, Center, ThemeIcon, Avatar } from "@mantine/core";
import { Link } from "react-router";
import { useRoleAccess } from "@/hooks/useRoleAccess";

import { getHoldingBalances, syncHoldingBalances, getManagers, getTransactions, deleteManager, restoreManager, getManagerHistory } from "@/lib/features/points-transfer/query";
import type { HoldingBalancesResponse, Manager, PointTransaction } from "@/lib/features/points-transfer/types";
import { TransferPointsSidePanel } from "./TransferPointsSidePanel";
import { MapManagerModal } from "./MapManagerModal";
import { EditManagerModal } from "./EditManagerModal";
import { IconArrowsRightLeft, IconEdit, IconTrash, IconLink, IconHistory, IconRefresh, IconSearch, IconBuildingBank } from "@tabler/icons-react";
import { notifications } from "@mantine/notifications";
import { modals } from "@mantine/modals";
import { useIsMobile } from "@/hooks/useIsMobile";
import { HistoryDrawer } from "./HistoryDrawer";
import { NotesCell } from "./NotesCell";
import { PageSizeSelect } from "./PageSizeSelect";

export const ManagerAdminTab = () => {
  const isMobile = useIsMobile();
  const { checkClientAccess, isSuperAdmin } = useRoleAccess();
  const canViewManagerAdmin = checkClientAccess("read", "points-transfer");
  // Super admins see every manager. Anyone else granted points-transfer access
  // is scoped by the API to the managers they mapped themselves.
  const isScopedToOwnManagers = !isSuperAdmin();

  const [balances, setBalances] = useState<HoldingBalancesResponse | null>(null);
  const [managers, setManagers] = useState<Manager[]>([]);
  const [loadingManagers, setLoadingManagers] = useState(true);
  const [loadingBalances, setLoadingBalances] = useState(true);
  const [transactions, setTransactions] = useState<PointTransaction[]>([]);
  const [txPage, setTxPage] = useState(1);
  const [loadingTxs, setLoadingTxs] = useState(false);
  const [totalTxs, setTotalTxs] = useState(0);
  const [txLimit, setTxLimit] = useState(5);

  const [panelOpened, setPanelOpened] = useState(false);
  const [defaultManagerId, setDefaultManagerId] = useState<string | null>(null);
  const [syncing, setSyncing] = useState(false);

  const [mapModalOpened, setMapModalOpened] = useState(false);
  const [mappingManager, setMappingManager] = useState<Manager | null>(null);

  const [editModalOpened, setEditModalOpened] = useState(false);
  const [editingManager, setEditingManager] = useState<Manager | null>(null);

  const [historyDrawerOpened, setHistoryDrawerOpened] = useState(false);
  const [historyManager, setHistoryManager] = useState<Manager | null>(null);
  const [historyData, setHistoryData] = useState<{ received: any[]; sent: any[] } | null>(null);
  const [loadingHistory, setLoadingHistory] = useState(false);

  const [managerSearchQuery, setManagerSearchQuery] = useState("");
  const [managerPage, setManagerPage] = useState(1);
  const [managerLimit, setManagerLimit] = useState(10);
  const [txSearchQuery, setTxSearchQuery] = useState("");

  // Must be re-armed in the effect body, not just initialised. StrictMode
  // runs mount -> cleanup -> mount, so without this the cleanup leaves the
  // ref permanently false and every `if (mountedRef.current)` guard below
  // is dead — which left the Sync button spinning forever.
  const mountedRef = useRef(true);
  useEffect(() => {
    mountedRef.current = true;
    return () => { mountedRef.current = false; };
  }, []);

  const fetchBalances = useCallback(async (silent = false) => {
    if (!silent) setLoadingBalances(true);
    try {
      const balRes = await getHoldingBalances();
      if (balRes.success && balRes.data) {
        setBalances(balRes.data);
        return balRes.data;
      }
    } catch (err) {
      console.error("Failed to load balances", err);
    } finally {
      if (!silent) setLoadingBalances(false);
    }
    return null;
  }, []);

  // Poll the (background) holding sync until it finishes. The balances endpoint
  // reports `syncing` while the detached ViewPoint fetch is running.
  const pollUntilSynced = useCallback(async () => {
    const POLL_MS = 3000;
    // The two holding accounts are fetched sequentially (ViewPoint 504s if
    // they overlap) at ~45-57s each, so a full sync is ~105s. Cap well above
    // that or a normal sync trips the "taking longer than expected" warning.
    const MAX_MS = 240000; // 4 min safety cap
    const start = Date.now();
    while (Date.now() - start < MAX_MS) {
      await new Promise((r) => setTimeout(r, POLL_MS));
      if (!mountedRef.current) return;
      const data = await fetchBalances(true);
      if (data && !data.syncing) {
        if (data.syncError) {
          notifications.show({ message: `Sync failed: ${data.syncError}`, color: "red" });
        } else {
          notifications.show({ message: "Balances synced successfully", color: "green" });
        }
        return;
      }
    }
    if (mountedRef.current) {
      notifications.show({ message: "Sync is taking longer than expected. Please refresh shortly.", color: "yellow" });
    }
  }, [fetchBalances]);

  const fetchManagers = useCallback(async () => {
    setLoadingManagers(true);
    try {
      const manRes = await getManagers();
      if (manRes.success && manRes.data) setManagers(manRes.data);
    } catch (err) {
      console.error("Failed to load managers", err);
    } finally {
      setLoadingManagers(false);
    }
  }, []);

  // `limit` is passed in rather than read from state so changing the page size
  // doesn't change this callback's identity and re-trigger the mount effect.
  const fetchTransactions = useCallback(async (page: number, search?: string, limit = 5) => {
    setLoadingTxs(true);
    try {
      const offset = (page - 1) * limit;
      const res = await getTransactions(limit, offset, search);
      if (res.success && res.data) {
        setTransactions(res.data.transactions);
        setTotalTxs(res.data.total);
      }
    } catch (err) {
      console.error("Failed to load transactions", err);
    } finally {
      setLoadingTxs(false);
    }
  }, []);

  useEffect(() => {
    if (canViewManagerAdmin) {
      fetchBalances().then((data) => {
        // If a background sync was already running when the page loaded, resume
        // polling so the UI reflects it finishing.
        if (data?.syncing && !syncing) {
          setSyncing(true);
          pollUntilSynced().finally(() => {
            if (mountedRef.current) setSyncing(false);
          });
        }
      });
      fetchManagers();
      fetchTransactions(1, txSearchQuery, txLimit);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [canViewManagerAdmin, fetchBalances, fetchManagers, fetchTransactions, txSearchQuery]);

  const openTransferPanel = (managerId: string | null = null) => {
    setDefaultManagerId(managerId);
    setPanelOpened(true);
  };

  // Deliberately not `window.confirm`: iOS Safari renders it as a cramped
  // system sheet titled with the origin, truncates long messages and ignores
  // page styling, so managers couldn't read who they were about to deactivate.
  const handleDeleteManager = (manager: Manager) => {
    modals.openConfirmModal({
      title: "Deactivate manager",
      centered: true,
      size: "sm",
      children: (
        <Stack gap={6}>
          <Text size="sm" fw={600}>
            {manager.first_name} {manager.last_name || ""}
          </Text>
          <Text size="sm" c="dimmed" style={{ wordBreak: "break-all" }}>{manager.email}</Text>
          <Text size="sm" mt="xs">
            They will lose access to points transfers. You can restore them later from the
            Deactivated Managers page.
          </Text>
        </Stack>
      ),
      labels: { confirm: "Deactivate", cancel: "Cancel" },
      confirmProps: { color: "red" },
      // Stacked full-width buttons on phones — side-by-side ones end up too
      // narrow to tap reliably once the labels wrap.
      groupProps: isMobile
        ? { align: "stretch" as const, style: { flexDirection: "column-reverse" as const } }
        : undefined,
      onConfirm: () => void performDeleteManager(manager),
    });
  };

  const performDeleteManager = async (manager: Manager) => {
    try {
      const res = await deleteManager(manager.id);
      if (res.success) {
        notifications.show({ color: "green", message: "Manager deactivated successfully" });
        fetchBalances();
        fetchManagers();
      } else {
        notifications.show({ color: "red", message: res.message || "Failed to deactivate manager" });
      }
    } catch (err) {
      notifications.show({ color: "red", message: "Error deactivating manager" });
    }
  };

  const handleRestoreManager = async (manager: Manager) => {
    try {
      const res = await restoreManager(manager.id);
      if (res.success) {
        notifications.show({ color: "green", message: "Manager restored successfully" });
        fetchBalances();
        fetchManagers();
      } else {
        notifications.show({ color: "red", message: res.message || "Failed to restore manager" });
      }
    } catch (err) {
      notifications.show({ color: "red", message: "Error restoring manager" });
    }
  };

  const handleViewHistory = async (manager: Manager) => {
    setHistoryManager(manager);
    setHistoryDrawerOpened(true);
    setLoadingHistory(true);
    setHistoryData(null);
    try {
      const res = await getManagerHistory(manager.id);
      if (res.success && res.data) {
        setHistoryData(res.data);
      }
    } catch (err) {
      notifications.show({ color: "red", message: "Failed to load manager transaction history" });
    } finally {
      setLoadingHistory(false);
    }
  };

  const activeManagers = managers.filter(m => !m.is_deleted);
  const mappedManagers = activeManagers.filter(m => m.viewpoint_account_id != null);
  const unmappedManagers = activeManagers.filter(m => m.viewpoint_account_id == null);
  const deletedManagers = managers.filter(m => m.is_deleted);

  const filteredMappedManagers = mappedManagers.filter(m => {
    const query = managerSearchQuery.toLowerCase().trim();
    if (!query) return true;
    const fullName = `${m.first_name} ${m.last_name || ""}`.toLowerCase();
    return (
      fullName.includes(query) ||
      m.email.toLowerCase().includes(query) ||
      (m.viewpoint_account_id && m.viewpoint_account_id.toLowerCase().includes(query)) ||
      (m.viewpoint_club && m.viewpoint_club.toLowerCase().includes(query))
    );
  });

  // The managers endpoint returns the full list, so paginate client side.
  const managerTotalPages = Math.ceil(filteredMappedManagers.length / managerLimit) || 1;
  const safeManagerPage = Math.min(managerPage, managerTotalPages);
  const pagedManagers = filteredMappedManagers.slice(
    (safeManagerPage - 1) * managerLimit,
    safeManagerPage * managerLimit,
  );
  const managerRangeStart = filteredMappedManagers.length === 0 ? 0 : (safeManagerPage - 1) * managerLimit + 1;
  const managerRangeEnd = Math.min(safeManagerPage * managerLimit, filteredMappedManagers.length);

  const openMapModal = () => {
    setMapModalOpened(true);
  };

  const handleTransferSuccess = () => {
    fetchBalances();
    fetchManagers();
    setTxPage(1);
    fetchTransactions(1, txSearchQuery, txLimit);
  };

  // The sync request stays open until the run settles (~105s) and comes back
  // with the final balances, so we paint them and drop the loader in the same
  // tick. Polling is only the fallback for when that request can't complete.
  const handleSyncBalances = async () => {
    setSyncing(true);
    notifications.show({
      message: "Syncing balances from ViewPoint — this takes about two minutes…",
      color: "blue",
    });
    try {
      const res = await syncHoldingBalances();

      if (res.success && res.data?.balances && !res.data.timedOut) {
        setBalances(res.data.balances);
        const syncError = res.data.balances.syncError;
        notifications.show(
          syncError
            ? { message: `Sync failed: ${syncError}`, color: "red" }
            : { message: "Balances synced successfully", color: "green" },
        );
        return;
      }

      // Either the server gave up waiting or the response was unusable — the
      // sync is still going server-side, so watch it the slow way.
      await pollUntilSynced();
    } catch (err) {
      // Most likely the connection dropped while the response was held open.
      // The sync keeps running on the server, so fall back to polling.
      console.error(err);
      await pollUntilSynced();
    } finally {
      if (mountedRef.current) setSyncing(false);
    }
  };

  if (!canViewManagerAdmin) {
    return (
      <Flex justify={"center"} align={"center"} py={50}>
        <Stack align="center" gap={6}>
          <Title order={4}>Access denied</Title>
          <Text c="dimmed">You do not have permission to view the dashboard.</Text>
        </Stack>
      </Flex>
    );
  }

  const holdingAccounts = [
    { key: "india", label: "India Holding Account", color: "orange", data: balances?.india },
    { key: "nonIndia", label: "Non-India Holding Account", color: "blue", data: balances?.nonIndia },
  ] as const;

  const totalTxPages = Math.ceil(totalTxs / txLimit) || 1;
  const txRangeStart = totalTxs === 0 ? 0 : (txPage - 1) * txLimit + 1;
  const txRangeEnd = Math.min(txPage * txLimit, totalTxs);

  return (
    <Stack gap="lg" p={{ base: "xs", sm: "md" }}>
      <Flex
        direction={{ base: "column", sm: "row" }}
        justify="space-between"
        align={{ base: "stretch", sm: "center" }}
        gap="sm"
      >
        <div>
          <Title order={2} fz={{ base: "h3", sm: "h2" }}>Admin Point Transfer</Title>
          <Text c="dimmed" size="sm">
            {isScopedToOwnManagers
              ? "Move points from the holding accounts to the managers you created."
              : "Move points from the holding accounts to mapped managers."}
          </Text>
        </div>
        <Group gap="sm" wrap="nowrap">
          <Button
            component={Link}
            to="/admin/points-transfer/deactivated"
            variant="outline"
            color="red"
            leftSection={<IconTrash size={16} />}
            flex={{ base: 1, sm: "0 0 auto" }}
          >
            Deactivated
          </Button>
          <Button
            leftSection={<IconArrowsRightLeft size={16} />}
            onClick={() => openTransferPanel(null)}
            flex={{ base: 1, sm: "0 0 auto" }}
          >
            Transfer Points
          </Button>
        </Group>
      </Flex>

      {/* Holding Balances */}
      <Stack gap="sm">
        <Flex
          direction={{ base: "column", sm: "row" }}
          justify="space-between"
          align={{ base: "stretch", sm: "center" }}
          gap="xs"
        >
          <Group gap="xs">
            <Title order={4}>Holding Balances</Title>
            {syncing && <Badge variant="light" color="blue" size="sm">Syncing…</Badge>}
          </Group>
          <Button
            size="sm"
            variant="light"
            leftSection={<IconRefresh size={16} />}
            loading={syncing}
            onClick={handleSyncBalances}
          >
            Sync Balances
          </Button>
        </Flex>
        <Grid gutter={{ base: "sm", sm: "md" }}>
          {holdingAccounts.map(({ key, label, color, data }) => (
            <Grid.Col key={key} span={{ base: 12, md: 6 }}>
              <Card shadow="sm" p={{ base: "md", sm: "lg" }} radius="md" withBorder h="100%">
                <Group justify="space-between" align="flex-start" wrap="nowrap">
                  <Stack gap={4} style={{ minWidth: 0 }}>
                    <Text fw={700} c="dimmed" fz={11} tt="uppercase" lts={0.4}>{label}</Text>
                    {loadingBalances ? (
                      <Loader size="sm" my={6} />
                    ) : (
                      <Text fw={700} fz={{ base: 28, sm: 34 }} lh={1.2}>
                        {data ? data.balance.toLocaleString() : "…"}
                      </Text>
                    )}
                  </Stack>
                  <ThemeIcon variant="light" color={color} size={42} radius="md">
                    <IconBuildingBank size={22} />
                  </ThemeIcon>
                </Group>
                <Flex
                  direction={{ base: "column", xs: "row" }}
                  justify="space-between"
                  gap={4}
                  mt="sm"
                >
                  <Text size="sm" c="dimmed">Account: {data?.account || "-"}</Text>
                  <Text size="sm" c="dimmed">
                    Last synced: {data?.lastSyncedAt ? new Date(data.lastSyncedAt).toLocaleString() : "Never"}
                  </Text>
                </Flex>
              </Card>
            </Grid.Col>
          ))}
        </Grid>
      </Stack>

      {/*  Managers */}
      <Card shadow="sm" p={{ base: "sm", sm: "lg" }} radius="md" withBorder>
        <Flex
          direction={{ base: "column", sm: "row" }}
          justify="space-between"
          align={{ base: "stretch", sm: "center" }}
          gap="sm"
          mb="md"
        >
          <Group gap="xs">
            <Title order={4}>Managers</Title>
            <Badge variant="light" color="gray" size="sm">{filteredMappedManagers.length}</Badge>
            {isScopedToOwnManagers && (
              <Tooltip label="You can only see and transfer to managers you created">
                <Badge variant="light" color="blue" size="sm">Created by you</Badge>
              </Tooltip>
            )}
          </Group>
          <Group gap="sm" wrap="nowrap">
            <TextInput
              placeholder="Search managers..."
              leftSection={<IconSearch size={14} />}
              value={managerSearchQuery}
              onChange={(e) => {
                setManagerSearchQuery(e.currentTarget.value);
                setManagerPage(1);
              }}
              size="xs"
              flex={{ base: 1, sm: "0 0 250px" }}
            />
            <Button size="xs" leftSection={<IconLink size={14} />} onClick={openMapModal}>Map Manager</Button>
          </Group>
        </Flex>
        <Table.ScrollContainer minWidth={760}>
          <Table striped highlightOnHover verticalSpacing="sm">
            <Table.Thead>
              <Table.Tr>
                <Table.Th>Name</Table.Th>
                <Table.Th>Email</Table.Th>
                <Table.Th>ViewPoint Club</Table.Th>
                <Table.Th>Account / Contact ID</Table.Th>
                <Table.Th w={170}>Actions</Table.Th>
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {loadingManagers ? (
                <Table.Tr>
                  <Table.Td colSpan={5}>
                    <Center py="lg"><Loader size="sm" /></Center>
                  </Table.Td>
                </Table.Tr>
              ) : filteredMappedManagers.length === 0 ? (
                <Table.Tr>
                  <Table.Td colSpan={5}>
                    <Text c="dimmed" size="sm" ta="center" py="lg">
                      {managerSearchQuery ? "No managers match your search query." : "No managers found. Add one to get started."}
                    </Text>
                  </Table.Td>
                </Table.Tr>
              ) : (
                pagedManagers.map((m) => (
                  <Table.Tr key={m.id}>
                    <Table.Td>
                      <Group gap="xs" wrap="nowrap">
                        <Avatar size={28} radius="xl" color="blue" variant="light">
                          {`${m.first_name?.[0] || ""}${m.last_name?.[0] || ""}`.toUpperCase()}
                        </Avatar>
                        <Text size="sm" fw={500}>{m.first_name} {m.last_name}</Text>
                      </Group>
                    </Table.Td>
                    <Table.Td><Text size="sm">{m.email}</Text></Table.Td>
                    <Table.Td>
                      {m.viewpoint_club ? <Badge color="teal" variant="light">{m.viewpoint_club}</Badge> : <Badge color="gray" variant="light">N/A</Badge>}
                    </Table.Td>
                    <Table.Td>
                      {m.viewpoint_account_id ? (
                        <Stack gap={0}>
                          <Text size="sm" fw={500}>Acc: {m.viewpoint_account_id}</Text>
                          <Text size="sm" c="dimmed">Contact: {m.viewpoint_contact_id}</Text>
                        </Stack>
                      ) : (
                        <Text size="sm" c="dimmed">Not linked</Text>
                      )}
                    </Table.Td>
                    <Table.Td>
                      <Group gap={8} wrap="nowrap">
                        <Tooltip label="Edit Manager">
                          <ActionIcon variant="light" color="blue" onClick={() => { setEditingManager(m); setEditModalOpened(true); }}>
                            <IconEdit size={16} />
                          </ActionIcon>
                        </Tooltip>
                        <Tooltip label="Delete Manager">
                          <ActionIcon variant="light" color="red" onClick={() => handleDeleteManager(m)}>
                            <IconTrash size={16} />
                          </ActionIcon>
                        </Tooltip>
                        <Tooltip label="View History">
                          <ActionIcon variant="light" color="violet" onClick={() => handleViewHistory(m)}>
                            <IconHistory size={16} />
                          </ActionIcon>
                        </Tooltip>
                        <Tooltip label="Transfer Points">
                          <ActionIcon variant="light" color="green" onClick={() => openTransferPanel(m.id)}>
                            <IconArrowsRightLeft size={16} />
                          </ActionIcon>
                        </Tooltip>
                      </Group>
                    </Table.Td>
                  </Table.Tr>
                ))
              )}
            </Table.Tbody>
          </Table>
        </Table.ScrollContainer>

        {!loadingManagers && filteredMappedManagers.length > 0 && (
          <Flex
            direction={{ base: "column", sm: "row" }}
            justify="space-between"
            align="center"
            gap="sm"
            mt="md"
          >
            <Group gap="md" wrap="wrap">
              <Text size="sm" c="dimmed">
                Showing {managerRangeStart}–{managerRangeEnd} of {filteredMappedManagers.length}
              </Text>
              <PageSizeSelect
                value={managerLimit}
                onChange={(v) => { setManagerLimit(v); setManagerPage(1); }}
              />
            </Group>
            <Pagination
              value={safeManagerPage}
              onChange={setManagerPage}
              total={managerTotalPages}
              size="sm"
              siblings={1}
              boundaries={1}
            />
          </Flex>
        )}
      </Card>

      {/* Transaction History */}
      <Card shadow="sm" p={{ base: "sm", sm: "lg" }} radius="md" withBorder>
        <Flex
          direction={{ base: "column", sm: "row" }}
          justify="space-between"
          align={{ base: "stretch", sm: "center" }}
          gap="sm"
          mb="md"
        >
          <Group gap="xs">
            <Title order={4}>Recent Point Transfers</Title>
            <Badge variant="light" color="gray" size="sm">{totalTxs}</Badge>
          </Group>
          <TextInput
            placeholder="Search transfers..."
            leftSection={<IconSearch size={14} />}
            value={txSearchQuery}
            onChange={(e) => {
              setTxSearchQuery(e.currentTarget.value);
              setTxPage(1);
              fetchTransactions(1, e.currentTarget.value, txLimit);
            }}
            size="xs"
            w={{ base: "100%", sm: 250 }}
          />
        </Flex>
        <Table.ScrollContainer minWidth={980}>
          <Table striped highlightOnHover verticalSpacing="sm">
            <Table.Thead>
              <Table.Tr>
                <Table.Th>Date</Table.Th>
                <Table.Th>Source Holding</Table.Th>
                <Table.Th>Initiated By</Table.Th>
                <Table.Th>Transfer To</Table.Th>
                <Table.Th>Application</Table.Th>
                <Table.Th>Points</Table.Th>
                <Table.Th>Status</Table.Th>
                <Table.Th>Notes</Table.Th>
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {loadingTxs ? (
                <Table.Tr>
                  <Table.Td colSpan={8}>
                    <Center py="lg"><Loader size="sm" /></Center>
                  </Table.Td>
                </Table.Tr>
              ) : transactions.length === 0 ? (
                <Table.Tr>
                  <Table.Td colSpan={8}>
                    <Text c="dimmed" size="sm" ta="center" py="lg">
                      {txSearchQuery ? "No transfers match your search." : "No transactions found."}
                    </Text>
                  </Table.Td>
                </Table.Tr>
              ) : (
                transactions.map((t) => (
                  <Table.Tr key={t.id}>
                    <Table.Td><Text size="sm" style={{ whiteSpace: "nowrap" }}>{new Date(t.created_at).toLocaleString()}</Text></Table.Td>
                    <Table.Td><Text size="sm">{t.source_holding_account}</Text></Table.Td>
                    <Table.Td>
                      <Tooltip label={t.initiator_email || ""}>
                        <Text size="sm">
                          {t.initiator_first_name ? `${t.initiator_first_name} ${t.initiator_last_name || ""}` : "Super Admin"}
                        </Text>
                      </Tooltip>
                    </Table.Td>
                    <Table.Td>
                      <Tooltip label={t.manager_email || ""}>
                        <Text size="sm">
                          {t.manager_first_name || t.first_name || ""} {t.manager_last_name || t.last_name || ""}
                        </Text>
                      </Tooltip>
                    </Table.Td>
                    <Table.Td>
                      <Badge variant="outline" color="blue">
                        {t.application || "Admin Console"}
                      </Badge>
                    </Table.Td>
                    <Table.Td fw={600} c="green" style={{ whiteSpace: "nowrap" }}>+{t.points.toLocaleString()}</Table.Td>
                    <Table.Td><Badge variant="light" color={t.status === "SUCCESS" ? "green" : "gray"}>{t.status}</Badge></Table.Td>
                    <Table.Td><NotesCell value={t.notes} maw={220} /></Table.Td>
                  </Table.Tr>
                ))
              )}
            </Table.Tbody>
          </Table>
        </Table.ScrollContainer>

        <Flex
          direction={{ base: "column", sm: "row" }}
          justify="space-between"
          align="center"
          gap="sm"
          mt="md"
        >
          <Group gap="md" wrap="wrap">
            <Text size="sm" c="dimmed">Showing {txRangeStart}–{txRangeEnd} of {totalTxs}</Text>
            <PageSizeSelect
              value={txLimit}
              onChange={(v) => {
                setTxLimit(v);
                setTxPage(1);
                fetchTransactions(1, txSearchQuery, v);
              }}
            />
          </Group>
          <Pagination
            value={txPage}
            onChange={(page) => {
              setTxPage(page);
              fetchTransactions(page, txSearchQuery, txLimit);
            }}
            total={totalTxPages}
            size="sm"
            siblings={1}
            boundaries={1}
          />
        </Flex>
      </Card>

      <TransferPointsSidePanel
        opened={panelOpened}
        onClose={() => setPanelOpened(false)}
        managers={mappedManagers}
        balances={balances}
        defaultManagerId={defaultManagerId}
        onSuccess={handleTransferSuccess}
      />

      <MapManagerModal
        opened={mapModalOpened}
        onClose={() => setMapModalOpened(false)}
        unmappedManagers={unmappedManagers}
        onSuccess={() => { fetchBalances(); fetchManagers(); }}
      />

      <EditManagerModal
        opened={editModalOpened}
        onClose={() => { setEditModalOpened(false); setEditingManager(null); }}
        manager={editingManager}
        onSuccess={() => { fetchBalances(); fetchManagers(); }}
      />

      <HistoryDrawer
        opened={historyDrawerOpened}
        onClose={() => setHistoryDrawerOpened(false)}
        manager={historyManager}
        loading={loadingHistory}
        data={historyData}
      />
    </Stack>
  );
};


