import { Waypoints } from "lucide-react";
import { ResponsiveContainer, Sankey, Tooltip, type SankeyLinkProps } from "recharts";
import { Text } from "@mantine/core";

import type { IOverviewRevenueFlow } from "@/types/overview";
import { chartTooltipStyle } from "./chart-style";
import { SummaryCard } from "./SummaryCard";
import {
  DIRECTION_COLORS,
  FLOW_FALLBACK_COLOR,
  FLOW_LABELS,
  FREIGHT_TYPE_COLORS,
} from "./flow-colors";

function formatEtb(amount: number) {
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "ETB",
    maximumFractionDigits: 0,
  }).format(amount);
}

interface SankeyNodeDatum {
  name: string;
  key: string;
  color: string;
}

/** Build recharts Sankey data: direction nodes on the left, freight types on the right. */
function toSankeyData(flows: IOverviewRevenueFlow[]) {
  const active = flows.filter((f) => f.amountEtb > 0);
  const nodes: SankeyNodeDatum[] = [];
  const indexByKey = new Map<string, number>();
  const nodeIndex = (key: string, color: string) => {
    const existing = indexByKey.get(key);
    if (existing != null) return existing;
    nodes.push({ name: FLOW_LABELS[key] ?? key, key, color });
    indexByKey.set(key, nodes.length - 1);
    return nodes.length - 1;
  };

  // Register directions first so they all land on the left column.
  for (const flow of active) {
    nodeIndex(flow.direction, DIRECTION_COLORS[flow.direction] ?? FLOW_FALLBACK_COLOR);
  }
  const links = active.map((flow) => ({
    source: indexByKey.get(flow.direction)!,
    target: nodeIndex(
      flow.freightType,
      FREIGHT_TYPE_COLORS[flow.freightType] ?? FLOW_FALLBACK_COLOR,
    ),
    value: flow.amountEtb,
  }));

  return { nodes, links };
}

function FlowNode({
  x,
  y,
  width,
  height,
  index,
  payload,
}: {
  x: number;
  y: number;
  width: number;
  height: number;
  index: number;
  payload: { name?: string; value?: number; color?: string };
}) {
  // Labels sit to the right of every bar: the right margin reserves room for
  // the last column, and the pale ribbons stay readable under the left one.
  return (
    <g key={`node-${index}`}>
      <rect x={x} y={y} width={width} height={height} fill={payload.color} rx={3} />
      <text
        x={x + width + 8}
        y={y + height / 2 - 6}
        textAnchor="start"
        dominantBaseline="central"
        fontSize={12}
        fontWeight={600}
        fill="#1f2937"
      >
        {payload.name}
      </text>
      <text
        x={x + width + 8}
        y={y + height / 2 + 9}
        textAnchor="start"
        dominantBaseline="central"
        fontSize={11}
        fill="var(--mantine-color-gray-6)"
      >
        {formatEtb(payload.value ?? 0)}
      </text>
    </g>
  );
}

/** Ribbon tinted by its source direction — the corridor keeps its color across the chart. */
function FlowLink({
  sourceX,
  targetX,
  sourceY,
  targetY,
  sourceControlX,
  targetControlX,
  linkWidth,
  index,
  payload,
}: SankeyLinkProps) {
  // Custom node fields (color) ride along on the layout node recharts hands back.
  const source = payload.source as { color?: string };
  return (
    <path
      key={`link-${index}`}
      d={`M${sourceX},${sourceY} C${sourceControlX},${sourceY} ${targetControlX},${targetY} ${targetX},${targetY}`}
      fill="none"
      stroke={source.color ?? FLOW_FALLBACK_COLOR}
      strokeOpacity={0.3}
      strokeWidth={linkWidth}
    />
  );
}

interface OverviewSankeyFlowProps {
  flows: IOverviewRevenueFlow[];
}

/**
 * Where the money runs: ETB revenue as ribbons from trade direction to
 * freight type. Ribbon thickness is proportional to revenue, so the biggest
 * corridor is unmissable.
 */
export function OverviewSankeyFlow({ flows }: OverviewSankeyFlowProps) {
  const data = toSankeyData(flows);

  return (
    <SummaryCard
      icon={Waypoints}
      accent="sky"
      title="Revenue flow"
      subtitle="Trade direction → freight type, sized by ETB revenue"
    >
      {data.links.length === 0 ? (
        <Text size="sm" c="dimmed" ta="center" py="xl">
          No revenue in this period
        </Text>
      ) : (
        <ResponsiveContainer width="100%" height={252}>
          <Sankey
            data={data}
            node={FlowNode}
            link={FlowLink}
            nodePadding={32}
            margin={{ top: 20, right: 96, bottom: 12, left: 4 }}
          >
            <Tooltip
              formatter={(value) => formatEtb(Number(value))}
              contentStyle={chartTooltipStyle}
            />
          </Sankey>
        </ResponsiveContainer>
      )}
    </SummaryCard>
  );
}
