import { useState, useEffect, useRef, useCallback } from 'react';
import {
  Title, Group, Stack, Text, Card, Loader, Center, Select, SimpleGrid, SegmentedControl,
} from '@mantine/core';
import { useQuery } from '@tanstack/react-query';
import {
  sankey as d3Sankey,
  sankeyLinkHorizontal,
  sankeyJustify,
  SankeyNode,
  SankeyLink,
} from 'd3-sankey';
import api from '../../services/api';

interface FlowNode {
  name: string;
  category: string;
}

interface FlowLink {
  source: number;
  target: number;
  value: number;
}

interface CashFlowData {
  nodes: FlowNode[];
  links: FlowLink[];
  total_income: number;
  total_expenses: number;
  net_cash_flow: number;
}

type SNode = SankeyNode<FlowNode, FlowLink>;
type SLink = SankeyLink<FlowNode, FlowLink>;

const CATEGORY_COLORS: Record<string, string> = {
  income: '#40c057',
  expense: '#fa5252',
  reserve: '#7950f2',
  transfer: '#228be6',
  net: '#868e96',
  operating: '#15aabf',
};

function getNodeColor(node: FlowNode): string {
  return CATEGORY_COLORS[node.category] || '#868e96';
}

export function SankeyPage() {
  const svgRef = useRef<SVGSVGElement | null>(null);
  const containerRef = useRef<HTMLDivElement | null>(null);
  const [dimensions, setDimensions] = useState({ width: 900, height: 500 });
  const [year, setYear] = useState(new Date().getFullYear().toString());
  const [source, setSource] = useState('actuals');
  const [fundFilter, setFundFilter] = useState('all');

  const yearOptions = Array.from({ length: 5 }, (_, i) => {
    const y = new Date().getFullYear() - 2 + i;
    return { value: String(y), label: String(y) };
  });

  const { data, isLoading, isError } = useQuery<CashFlowData>({
    queryKey: ['sankey', year, source, fundFilter],
    queryFn: async () => {
      const params = new URLSearchParams({ year });
      if (source !== 'actuals') params.set('source', source);
      if (fundFilter !== 'all') params.set('fundType', fundFilter);
      const { data } = await api.get(`/reports/cash-flow-sankey?${params}`);
      return data;
    },
  });

  // Resize observer
  useEffect(() => {
    const container = containerRef.current;
    if (!container) return;
    const observer = new ResizeObserver((entries) => {
      for (const entry of entries) {
        const { width } = entry.contentRect;
        if (width > 0) {
          setDimensions({ width: Math.max(width - 32, 400), height: Math.max(400, Math.min(600, width * 0.5)) });
        }
      }
    });
    observer.observe(container);
    return () => observer.disconnect();
  }, []);

  const renderSankey = useCallback(() => {
    if (!data || !svgRef.current || data.nodes.length === 0 || data.links.length === 0) return;

    const { width, height } = dimensions;
    const margin = { top: 10, right: 150, bottom: 10, left: 150 };
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;

    // Build sankey layout
    const sankeyLayout = d3Sankey<FlowNode, FlowLink>()
      .nodeWidth(20)
      .nodePadding(12)
      .nodeAlign(sankeyJustify)
      .extent([[0, 0], [innerWidth, innerHeight]]);

    // Deep clone data so d3 can mutate it
    const graph = sankeyLayout({
      nodes: data.nodes.map((d) => ({ ...d })),
      links: data.links.map((d) => ({ ...d })),
    });

    const svg = svgRef.current;
    // Clear previous content
    while (svg.firstChild) svg.removeChild(svg.firstChild);

    const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
    g.setAttribute('transform', `translate(${margin.left},${margin.top})`);
    svg.appendChild(g);

    // Render links
    const linkPath = sankeyLinkHorizontal<SLink, SNode>();
    (graph.links as SLink[]).forEach((link) => {
      const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
      const d = linkPath(link as any);
      if (d) path.setAttribute('d', d);
      const sourceNode = link.source as SNode;
      path.setAttribute('fill', 'none');
      path.setAttribute('stroke', getNodeColor(sourceNode));
      path.setAttribute('stroke-opacity', '0.3');
      path.setAttribute('stroke-width', String(Math.max(1, (link as any).width || 1)));

      // Hover effect
      path.addEventListener('mouseenter', () => {
        path.setAttribute('stroke-opacity', '0.6');
      });
      path.addEventListener('mouseleave', () => {
        path.setAttribute('stroke-opacity', '0.3');
      });

      // Tooltip
      const title = document.createElementNS('http://www.w3.org/2000/svg', 'title');
      const sn = link.source as SNode;
      const tn = link.target as SNode;
      const val = (link.value || 0).toLocaleString('en-US', { style: 'currency', currency: 'USD' });
      title.textContent = `${sn.name} → ${tn.name}: ${val}`;
      path.appendChild(title);

      g.appendChild(path);
    });

    // Render nodes
    (graph.nodes as SNode[]).forEach((node) => {
      const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
      rect.setAttribute('x', String(node.x0 || 0));
      rect.setAttribute('y', String(node.y0 || 0));
      rect.setAttribute('width', String((node.x1 || 0) - (node.x0 || 0)));
      rect.setAttribute('height', String(Math.max(1, (node.y1 || 0) - (node.y0 || 0))));
      rect.setAttribute('fill', getNodeColor(node));
      rect.setAttribute('rx', '2');

      const title = document.createElementNS('http://www.w3.org/2000/svg', 'title');
      const val = (node.value || 0).toLocaleString('en-US', { style: 'currency', currency: 'USD' });
      title.textContent = `${node.name}: ${val}`;
      rect.appendChild(title);
      g.appendChild(rect);

      // Label
      const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
      const isLeftSide = (node.x0 || 0) < innerWidth / 2;
      text.setAttribute('x', String(isLeftSide ? (node.x0 || 0) - 6 : (node.x1 || 0) + 6));
      text.setAttribute('y', String(((node.y0 || 0) + (node.y1 || 0)) / 2));
      text.setAttribute('dy', '0.35em');
      text.setAttribute('text-anchor', isLeftSide ? 'end' : 'start');
      text.setAttribute('font-size', '11');
      text.setAttribute('fill', '#495057');
      text.textContent = node.name;
      g.appendChild(text);
    });
  }, [data, dimensions]);

  useEffect(() => {
    renderSankey();
  }, [renderSankey]);

  const fmt = (v: number) =>
    (v || 0).toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 0 });

  if (isLoading) return <Center h={300}><Loader /></Center>;

  // Fallback if no data from API yet — show a helpful empty state
  const hasData = data && data.nodes.length > 0 && data.links.length > 0;

  return (
    <Stack>
      <Group justify="space-between">
        <Title order={2}>Cash Flow Visualization</Title>
        <Select data={yearOptions} value={year} onChange={(v) => v && setYear(v)} w={120} />
      </Group>

      <Group>
        <Text size="sm" fw={500}>Data source:</Text>
        <SegmentedControl
          size="sm"
          value={source}
          onChange={setSource}
          data={[
            { label: 'Actuals', value: 'actuals' },
            { label: 'Budget', value: 'budget' },
            { label: 'Forecast', value: 'forecast' },
          ]}
        />
        <Text size="sm" fw={500} ml="md">Fund:</Text>
        <SegmentedControl
          size="sm"
          value={fundFilter}
          onChange={setFundFilter}
          data={[
            { label: 'All Funds', value: 'all' },
            { label: 'Operating', value: 'operating' },
            { label: 'Reserve', value: 'reserve' },
          ]}
        />
      </Group>

      <SimpleGrid cols={{ base: 1, sm: 3 }}>
        <Card withBorder p="md">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Total Income</Text>
          <Text fw={700} size="xl" c="green">{fmt(data?.total_income || 0)}</Text>
        </Card>
        <Card withBorder p="md">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Total Expenses</Text>
          <Text fw={700} size="xl" c="red">{fmt(data?.total_expenses || 0)}</Text>
        </Card>
        <Card withBorder p="md">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Net Cash Flow</Text>
          <Text fw={700} size="xl" c={(data?.net_cash_flow || 0) >= 0 ? 'green' : 'red'}>
            {fmt(data?.net_cash_flow || 0)}
          </Text>
        </Card>
      </SimpleGrid>

      <Card withBorder p="md" ref={containerRef}>
        {isError ? (
          <Center h={300}>
            <Text c="dimmed">Unable to load cash flow data. Ensure the reports API is available.</Text>
          </Center>
        ) : !hasData ? (
          <Center h={300}>
            <Stack align="center" gap="sm">
              <Text c="dimmed" size="lg">No cash flow data for {year}</Text>
              <Text c="dimmed" size="sm">
                Record income and expense transactions to see the Sankey diagram.
              </Text>
            </Stack>
          </Center>
        ) : (
          <svg
            ref={svgRef}
            width={dimensions.width}
            height={dimensions.height}
            style={{ display: 'block', margin: '0 auto' }}
          />
        )}
      </Card>

      <Card withBorder p="sm">
        <Group gap="lg">
          {Object.entries(CATEGORY_COLORS).map(([key, color]) => (
            <Group key={key} gap={4}>
              <div style={{ width: 12, height: 12, borderRadius: 2, background: color }} />
              <Text size="xs" tt="capitalize">{key}</Text>
            </Group>
          ))}
        </Group>
      </Card>
    </Stack>
  );
}
