import {
  Alert,
  Card,
  Grid,
  Group,
  Progress,
  SegmentedControl,
  Skeleton,
  Stack,
  Table,
  Text,
  Title,
} from "@mantine/core";
import {
  IconGift,
  IconInfoCircle,
  IconLink,
  IconUserCheck,
  IconUsersGroup,
} from "@tabler/icons-react";
import { useState } from "react";
import {
  Area,
  AreaChart,
  Bar,
  BarChart,
  CartesianGrid,
  Cell,
  LabelList,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from "recharts";
import { usePromoTheme } from "@/routes/promo-code-campaigns/_components/appearance";
import {
  StatTiles,
  type StatTileSpec,
} from "@/routes/promo-code-campaigns/_components/StatTiles";
import styles from "@/routes/promo-code-campaigns/_components/promo.module.css";
import type { ReferralInviteAnalytics } from "@/lib/features/member-referral-invites/types";

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

/** Bars sized from content, so a short chart does not pad the card. */
const BAR_ROW = 34;
const BAR_CHROME = 52;

type Metric = "captured" | "registered" | "credited";

const METRIC_LABEL: Record<Metric, string> = {
  captured: "Emails captured",
  registered: "Registered",
  credited: "Successful referrals",
};

export default function InviteAnalytics({
  data,
  loading,
  onSelectReferrer,
}: {
  data: ReferralInviteAnalytics | null;
  loading: boolean;
  onSelectReferrer: (membershipNumber: string) => void;
}) {
  const { series } = usePromoTheme();
  const [metric, setMetric] = useState<Metric>("captured");

  if (loading && !data) {
    return (
      <Stack gap="md">
        <Skeleton h={104} radius="md" />
        <Skeleton h={260} radius="md" />
      </Stack>
    );
  }
  if (!data) return null;

  const colors = series(
    Math.max(4, data.bySource.length, data.topReferrers.length),
  );

  const tiles: StatTileSpec[] = [
    {
      key: "captured",
      label: "Emails captured",
      value: data.totalCaptured,
      color: colors[0].from,
      colorTo: colors[0].to,
      icon: <IconLink size={18} stroke={1.8} />,
      // Not "distinct emails": the table is uniquely indexed on LOWER(email),
      // so that figure can only ever repeat the one above it.
      hint: `across ${fmtInt(data.activeCodes)} referral link${data.activeCodes === 1 ? "" : "s"}`,
    },
    {
      key: "referrers",
      label: "Referrers",
      value: data.uniqueReferrers,
      color: colors[1].from,
      colorTo: colors[1].to,
      icon: <IconUsersGroup size={18} stroke={1.8} />,
      hint: data.uniqueReferrers
        ? `${(data.totalCaptured / data.uniqueReferrers).toFixed(1)} captures each`
        : undefined,
    },
    {
      key: "registered",
      label: "Registered",
      value: data.registered,
      color: colors[2].from,
      colorTo: colors[2].to,
      icon: <IconUserCheck size={18} stroke={1.8} />,
      percent: data.registrationRatePct,
      hint: `${data.registrationRatePct}% of captures have an account`,
    },
    {
      key: "credited",
      label: "Successful referrals",
      value: data.credited,
      color: colors[3].from,
      colorTo: colors[3].to,
      icon: <IconGift size={18} stroke={1.8} />,
      percent: data.creditedRatePct,
      hint: `${data.creditedRatePct}% end to end`,
    },
  ];

  const sources = data.bySource.slice(0, 8);
  const referrers = data.topReferrers.slice(0, 8).map((r) => ({
    ...r,
    label: r.name ?? r.membershipNumber ?? r.email ?? "Unknown",
  }));

  /*
   * The funnel is a strip, not a chart.
   *
   * Three stages that each contain the next do not divide a whole, so a pie
   * would misrepresent them; and at three bars a chart is mostly axis. The strip
   * carries count and drop-off on one line and reads the same at any volume.
   */
  const stages = [
    { key: "captured", label: "Email captured", value: data.totalCaptured },
    { key: "registered", label: "Registered", value: data.registered },
    { key: "credited", label: "Successful referral", value: data.credited },
  ];

  return (
    <Stack gap="md">
      <StatTiles tiles={tiles} loading={loading && !data} />

      <Grid gutter="md">
        <Grid.Col span={{ base: 12, lg: 5 }}>
          <Card className={styles.sectionCard} p="md" h="100%">
            <Stack gap="sm">
              <Stack gap={0}>
                <Title order={5}>Referral funnel</Title>
                <Text size="xs" c="dimmed">
                  Someone opened a member's link and gave their email. What
                  happened next.
                </Text>
              </Stack>

              <Stack gap="xs">
                {stages.map((stage, i) => {
                  const base = stages[0].value;
                  const share = base ? (stage.value / base) * 100 : 0;
                  const previous = i > 0 ? stages[i - 1].value : null;
                  const stepPct =
                    previous !== null && previous > 0
                      ? (stage.value / previous) * 100
                      : null;
                  return (
                    <Group key={stage.key} gap="sm" wrap="nowrap" align="center">
                      <Text size="sm" w={130} lineClamp={1} fw={600}>
                        {stage.label}
                      </Text>
                      <Progress
                        value={share}
                        size="lg"
                        radius="sm"
                        color={colors[i]?.from ?? "teal"}
                        style={{ flex: 1 }}
                      />
                      <Text size="sm" fw={700} w={56} ta="right" className={styles.num}>
                        {fmtInt(stage.value)}
                      </Text>
                      <Text size="xs" c="dimmed" w={58} ta="right">
                        {stepPct === null ? "" : `→ ${stepPct.toFixed(1)}%`}
                      </Text>
                    </Group>
                  );
                })}
              </Stack>


            </Stack>
          </Card>
        </Grid.Col>

        <Grid.Col span={{ base: 12, lg: 7 }}>
          <Card className={styles.sectionCard} p="md" h="100%">
            <Stack gap="sm">
              <Group justify="space-between" align="center" wrap="wrap">
                <Stack gap={0}>
                  <Title order={5}>Over time</Title>
                  <Text size="xs" c="dimmed">
                    By the day the email was captured
                  </Text>
                </Stack>
                <SegmentedControl
                  size="xs"
                  value={metric}
                  onChange={(v) => setMetric(v as Metric)}
                  data={[
                    { value: "captured", label: "Captured" },
                    { value: "registered", label: "Registered" },
                    { value: "credited", label: "Successful" },
                  ]}
                />
              </Group>

              {data.byDay.length === 0 ? (
                <Text c="dimmed" size="sm">
                  No captures in this range.
                </Text>
              ) : (
                <ResponsiveContainer width="100%" height={240}>
                  <AreaChart data={data.byDay} margin={{ left: 4, right: 12, top: 8 }}>
                    <defs>
                      <linearGradient id="captureFill" x1="0" y1="0" x2="0" y2="1">
                        <stop offset="0%" stopColor={colors[0].from} stopOpacity={0.45} />
                        <stop offset="100%" stopColor={colors[0].to} stopOpacity={0.04} />
                      </linearGradient>
                    </defs>
                    <CartesianGrid strokeDasharray="3 3" vertical={false} opacity={0.4} />
                    <XAxis
                      dataKey="day"
                      fontSize={11}
                      tickLine={false}
                      tickFormatter={(day: string) => day.slice(5)}
                      minTickGap={24}
                    />
                    <YAxis fontSize={11} tickLine={false} allowDecimals={false} width={40} />
                    <Tooltip
                      formatter={(value) => [
                        Number(value).toLocaleString("en-US"),
                        METRIC_LABEL[metric],
                      ]}
                    />
                    <Area
                      type="monotone"
                      dataKey={metric}
                      stroke={colors[0].from}
                      strokeWidth={2}
                      fill="url(#captureFill)"
                    />
                  </AreaChart>
                </ResponsiveContainer>
              )}
            </Stack>
          </Card>
        </Grid.Col>
      </Grid>

      <Grid gutter="md">
        <Grid.Col span={{ base: 12, lg: 7 }}>
          <Card className={styles.sectionCard} p="md" h="100%">
            <Stack gap="sm" h="100%">
              <Stack gap={0}>
                <Title order={5}>Top referrers</Title>
                <Text size="xs" c="dimmed">
                  By emails captured. Click a bar to filter the table to them.
                </Text>
              </Stack>
              {referrers.length === 0 ? (
                <Text c="dimmed" size="sm">
                  No referrers in this range.
                </Text>
              ) : (
                <div
                  style={{ flex: 1, minHeight: referrers.length * BAR_ROW + BAR_CHROME }}
                >
                  <ResponsiveContainer width="100%" height="100%">
                    <BarChart
                      data={referrers}
                      layout="vertical"
                      margin={{ left: 8, right: 34, top: 4 }}
                      barCategoryGap="28%"
                    >
                      <CartesianGrid strokeDasharray="3 3" horizontal={false} opacity={0.4} />
                      <XAxis type="number" allowDecimals={false} fontSize={12} />
                      <YAxis
                        type="category"
                        dataKey="label"
                        width={140}
                        fontSize={11}
                        tickLine={false}
                      />
                      <Tooltip
                        cursor={{ fillOpacity: 0.06 }}
                        formatter={(value, _n, item) => {
                          const p = item?.payload as {
                            registered?: number;
                            credited?: number;
                          };
                          return [
                            `${Number(value).toLocaleString("en-US")} captured · ${p?.registered ?? 0
                            } registered · ${p?.credited ?? 0} credited`,
                            "Referrer",
                          ];
                        }}
                      />
                      <Bar dataKey="captured" radius={[0, 6, 6, 0]} maxBarSize={22}>
                        {referrers.map((r, i) => (
                          <Cell
                            key={r.membershipNumber ?? r.label}
                            fill={colors[i % colors.length].from}
                            cursor={r.membershipNumber ? "pointer" : undefined}
                            onClick={() =>
                              r.membershipNumber && onSelectReferrer(r.membershipNumber)
                            }
                          />
                        ))}
                        <LabelList
                          dataKey="captured"
                          position="right"
                          fontSize={11}
                          formatter={(v) => Number(v).toLocaleString("en-US")}
                        />
                      </Bar>
                    </BarChart>
                  </ResponsiveContainer>
                </div>
              )}
            </Stack>
          </Card>
        </Grid.Col>

        <Grid.Col span={{ base: 12, lg: 5 }}>
          <Card className={styles.tableCard} p={0} h="100%">
            <Table.ScrollContainer minWidth={420}>
              <Table highlightOnHover verticalSpacing="sm" horizontalSpacing="md">
                <Table.Thead className={styles.tableHead}>
                  <Table.Tr>
                    <Table.Th>Where the link was opened</Table.Th>
                    <Table.Th ta="right">Captured</Table.Th>
                    <Table.Th ta="right">Registered</Table.Th>
                  </Table.Tr>
                </Table.Thead>
                <Table.Tbody>
                  {sources.map((s) => (
                    <Table.Tr key={s.source}>
                      <Table.Td>{s.source}</Table.Td>
                      <Table.Td ta="right" className={styles.num}>
                        {fmtInt(s.captured)}
                      </Table.Td>
                      <Table.Td ta="right" className={styles.num}>
                        {fmtInt(s.registered)}
                        <Text component="span" size="xs" c="dimmed">
                          {s.captured
                            ? ` (${((s.registered / s.captured) * 100).toFixed(0)}%)`
                            : ""}
                        </Text>
                      </Table.Td>
                    </Table.Tr>
                  ))}
                  {sources.length === 0 && (
                    <Table.Tr>
                      <Table.Td colSpan={3}>
                        <Text c="dimmed" ta="center" py="md" size="sm">
                          No source recorded on these captures.
                        </Text>
                      </Table.Td>
                    </Table.Tr>
                  )}
                </Table.Tbody>
              </Table>
            </Table.ScrollContainer>
          </Card>
        </Grid.Col>
      </Grid>
    </Stack>
  );
}
