import {
  Alert,
  Anchor,
  Badge,
  Card,
  Center,
  Group,
  Loader,
  SegmentedControl,
  Stack,
  Table,
  Text,
  Title,
} from "@mantine/core";
import { IconAlertTriangle } from "@tabler/icons-react";
import { Link } from "react-router";
import TablePaginationFooter from "@/components/TablePaginationFooter";
import styles from "@/routes/promo-code-campaigns/_components/promo.module.css";
import { formatRevenue } from "@/lib/export/eventAnalyticsSheets";
import {
  formatDateParam,
  type JourneysResponse,
} from "@/lib/features/event-analytics/types";

const fmtInt = (n: number) => n.toLocaleString("en-US");

/*
 * "28 Oct 2026 11:04", not "2026-10-28 11:04".
 *
 * One line here rather than two: these are three step columns side by side,
 * and stacking each would treble the height of every row.
 */
const fmtDateTime = (iso: string | null) => {
  if (!iso) return "—";
  const [date, time = ""] = iso.split("T");
  return `${formatDateParam(date) ?? date} ${time.slice(0, 5)}`.trim();
};

/** Hours as something readable — "2.5 h" is worse than "2h 30m" at a glance. */
function formatElapsed(hours: number | null): string {
  if (hours === null) return "—";
  if (hours < 1) return `${Math.round(hours * 60)}m`;
  if (hours < 48) {
    const h = Math.floor(hours);
    const m = Math.round((hours - h) * 60);
    return m ? `${h}h ${m}m` : `${h}h`;
  }
  return `${(hours / 24).toFixed(1)} days`;
}

export type JourneyOutcome = "purchased" | "held" | "cart";

const OUTCOME: Record<
  JourneyOutcome,
  { label: string; color: string; description: string }
> = {
  purchased: {
    label: "Booked",
    color: "teal",
    description: "Reached purchase",
  },
  held: {
    label: "Dropped at hold",
    color: "yellow",
    description: "Held a booking but never paid",
  },
  cart: {
    label: "Dropped at cart",
    color: "gray",
    description: "Added to cart and went no further",
  },
};

/**
 * One row per booking journey, showing where it stopped and whose it was.
 *
 * The funnel above says how many dropped; this says which ones, so a drop-off
 * figure can be followed through to the member it belongs to rather than ending
 * as a number.
 */
export default function JourneyTable({
  data,
  loading,
  outcome,
  onOutcomeChange,
  page,
  pageSize,
  onPageChange,
  onPageSizeChange,
  /** Carried onto member links so the back-trip keeps the current filters. */
  searchSuffix = "",
}: {
  data: JourneysResponse | null;
  loading: boolean;
  outcome: JourneyOutcome | null;
  onOutcomeChange: (next: JourneyOutcome | null) => void;
  page: number;
  pageSize: number;
  onPageChange: (page: number) => void;
  onPageSizeChange: (size: number) => void;
  searchSuffix?: string;
}) {
  const rows = data?.rows ?? [];

  return (
    <Stack gap="sm">
      <Group justify="space-between" align="center" wrap="wrap">
        <Stack gap={0}>
          <Title order={5}>Journeys ({fmtInt(data?.total ?? 0)})</Title>
          <Text size="xs" c="dimmed">
            One row per cart, showing how far it got.
          </Text>
        </Stack>
        <SegmentedControl
          size="xs"
          value={outcome ?? "all"}
          onChange={(v) => onOutcomeChange(v === "all" ? null : (v as JourneyOutcome))}
          data={[
            { value: "all", label: "All" },
            { value: "purchased", label: "Booked" },
            { value: "held", label: "Dropped at hold" },
            { value: "cart", label: "Dropped at cart" },
          ]}
        />
      </Group>

      {data?.truncated && (
        // A capped read must not pass as the whole set.
        <Alert color="yellow" variant="light" icon={<IconAlertTriangle size={16} />} p="xs">
          <Text size="xs">
            More journeys matched than could be read. These are the most recent —
            narrow the date range for a complete list.
          </Text>
        </Alert>
      )}

      {loading && !data ? (
        <Center py="xl">
          <Loader size="sm" />
        </Center>
      ) : (
        <>
          <Card className={styles.tableCard} p={0}>
            <Table.ScrollContainer minWidth={1040}>
              <Table highlightOnHover verticalSpacing="sm" horizontalSpacing="md">
                <Table.Thead className={styles.tableHead}>
                  <Table.Tr>
                    <Table.Th>Outcome</Table.Th>
                    <Table.Th>Member</Table.Th>
                    <Table.Th>Property</Table.Th>
                    <Table.Th>Campaign</Table.Th>
                    <Table.Th>Added to cart</Table.Th>
                    <Table.Th>Held</Table.Th>
                    <Table.Th>Purchased</Table.Th>
                    <Table.Th ta="right">Time to book</Table.Th>
                    <Table.Th ta="right">Revenue</Table.Th>
                  </Table.Tr>
                </Table.Thead>
                <Table.Tbody>
                  {rows.map((row) => {
                    const meta = OUTCOME[row.outcome];
                    return (
                      <Table.Tr key={row.journeyId}>
                        <Table.Td>
                          <Badge variant="light" color={meta.color} title={meta.description}>
                            {meta.label}
                          </Badge>
                        </Table.Td>
                        <Table.Td>
                          {row.memberId ? (
                            <Stack gap={0}>
                              <Anchor
                                component={Link}
                                to={`/admin/event-analytics/members/${encodeURIComponent(row.memberId)}${searchSuffix}`}
                                size="sm"
                                fw={600}
                                lineClamp={1}
                              >
                                {row.memberName ?? row.memberId}
                              </Anchor>
                              {row.memberName && (
                                <Text size="xs" c="dimmed">
                                  {row.memberId}
                                </Text>
                              )}
                            </Stack>
                          ) : (
                            <Text size="sm" c="dimmed">
                              —
                            </Text>
                          )}
                        </Table.Td>
                        <Table.Td>
                          <Text size="sm" lineClamp={1}>
                            {row.propertyName ?? "—"}
                          </Text>
                        </Table.Td>
                        <Table.Td>
                          <Text size="sm" c={row.utmSource ? undefined : "dimmed"}>
                            {row.utmSource
                              ? `${row.utmSource}${row.utmMedium ? ` / ${row.utmMedium}` : ""}`
                              : "Direct"}
                          </Text>
                        </Table.Td>
                        <Table.Td>{fmtDateTime(row.cartAt)}</Table.Td>
                        {/* Dimmed when absent, so the row reads as a trail that
                            stops rather than a row with gaps in it. */}
                        <Table.Td>
                          <Text size="sm" c={row.holdAt ? undefined : "dimmed"}>
                            {fmtDateTime(row.holdAt)}
                          </Text>
                        </Table.Td>
                        <Table.Td>
                          <Text size="sm" c={row.purchaseAt ? undefined : "dimmed"}>
                            {fmtDateTime(row.purchaseAt)}
                          </Text>
                        </Table.Td>
                        <Table.Td ta="right" className={styles.num}>
                          <Text size="sm" c={row.hoursToPurchase === null ? "dimmed" : undefined}>
                            {formatElapsed(row.hoursToPurchase)}
                          </Text>
                        </Table.Td>
                        <Table.Td ta="right">
                          <Text size="sm">{formatRevenue(row.revenueByCurrency)}</Text>
                        </Table.Td>
                      </Table.Tr>
                    );
                  })}
                  {rows.length === 0 && (
                    <Table.Tr>
                      <Table.Td colSpan={9}>
                        <Text c="dimmed" ta="center" py="md">
                          No journeys match these filters.
                        </Text>
                      </Table.Td>
                    </Table.Tr>
                  )}
                </Table.Tbody>
              </Table>
            </Table.ScrollContainer>
          </Card>

          <TablePaginationFooter
            total={data?.total ?? 0}
            page={page}
            totalPages={data?.totalPages ?? 1}
            pageSize={pageSize}
            onPageChange={onPageChange}
            onPageSizeChange={onPageSizeChange}
          />
        </>
      )}
    </Stack>
  );
}
