import { useMemo } from 'react';
import type { Node } from '@xyflow/react';
import type { AttributeDAG, DAGNode } from '../../types';

interface LayoutConfig {
  nodeHeight: number;
  headerGap: number;
  headerHeight: number;
  nodeSpacing: number;
  fontSize: number;
  isDark: boolean;
}

const COLOR_PALETTE = [
  { dark: '#177ddc', light: '#1890ff' }, // blue
  { dark: '#854eca', light: '#722ed1' }, // purple
  { dark: '#13a8a8', light: '#13c2c2' }, // cyan
  { dark: '#d87a16', light: '#fa8c16' }, // orange
  { dark: '#49aa19', light: '#52c41a' }, // green
  { dark: '#1677ff', light: '#1890ff' }, // blue
  { dark: '#eb2f96', light: '#f759ab' }, // magenta
  { dark: '#faad14', light: '#ffc53d' }, // gold
  { dark: '#a0d911', light: '#bae637' }, // lime
];

function darken(hex: string, amount: number): string {
  const num = parseInt(hex.slice(1), 16);
  const r = Math.max(0, ((num >> 16) & 0xff) - Math.floor(255 * amount));
  const g = Math.max(0, ((num >> 8) & 0xff) - Math.floor(255 * amount));
  const b = Math.max(0, (num & 0xff) - Math.floor(255 * amount));
  return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
}

export function useDAGLayout(
  data: AttributeDAG | null,
  config: LayoutConfig
): Node[] {
  return useMemo(() => {
    if (!data) return [];

    const {
      nodeHeight,
      headerGap,
      headerHeight,
      nodeSpacing,
      fontSize,
      isDark,
    } = config;

    const nodes: Node[] = [];
    const sortedCategories = [...data.categories].sort((a, b) => a.order - b.order);

    // Build category color map
    const categoryColors: Record<string, { fill: string; stroke: string }> = {};
    sortedCategories.forEach((cat, index) => {
      const paletteIndex = index % COLOR_PALETTE.length;
      const color = isDark
        ? COLOR_PALETTE[paletteIndex].dark
        : COLOR_PALETTE[paletteIndex].light;
      categoryColors[cat.name] = {
        fill: color,
        stroke: darken(color, 0.15),
      };
    });

    // Group nodes by category
    const nodesByCategory: Record<string, DAGNode[]> = {};
    for (const node of data.nodes) {
      if (!nodesByCategory[node.category]) {
        nodesByCategory[node.category] = [];
      }
      nodesByCategory[node.category].push(node);
    }

    // Sort nodes within each category by order
    for (const cat of Object.keys(nodesByCategory)) {
      nodesByCategory[cat].sort((a, b) => a.order - b.order);
    }

    // Calculate max column height for centering
    const maxNodesInColumn = Math.max(
      ...sortedCategories.map((cat) => (nodesByCategory[cat.name] || []).length),
      1
    );
    const maxTotalHeight = maxNodesInColumn * (nodeHeight + nodeSpacing) - nodeSpacing;
    const contentStartY = headerHeight + headerGap + 20; // Added extra top padding

    // Layout constants - INCREASED spacing
    const colStep = 340; // Reduced from 400
    const nodeWidth = 240;
    const headerWidth = 260;
    const groupWidth = 300; // Reduced from 360 to be less "too wide"

    // Helper function for column X position (Center of the column)
    const getColumnX = (colIndex: number) => colIndex * colStep;

    // 0. Add Group Nodes (Backgrounds) - Rendered first
    sortedCategories.forEach((cat, colIndex) => {
      const categoryNodes = nodesByCategory[cat.name] || [];
      const columnX = getColumnX(colIndex + 1); // +1 because column 0 is query

      // Calculate group height to include header and attributes
      const nodesCount = categoryNodes.length;
      const nodesHeight = Math.max(
        nodesCount * (nodeHeight + nodeSpacing) - nodeSpacing,
        0
      );

      // Start group above the header (header is at y=0)
      const groupStartY = -20;
      const groupPaddingBottom = 20;

      // Total height = distance from startY to contentStart + nodes height + bottom padding
      const groupHeight = (contentStartY - groupStartY) + nodesHeight + groupPaddingBottom;

      nodes.push({
        id: `group-${cat.name}`,
        type: 'group',
        position: {
          x: columnX - groupWidth / 2, // Centered
          y: groupStartY
        },
        data: {
          label: '', // Label is handled by header node
          color: categoryColors[cat.name]?.fill || '#666',
          width: groupWidth,
          height: Math.max(groupHeight, 100), // Ensure min height
          isDark,
        },
        draggable: false,
        selectable: false,
        zIndex: -1,
      });
    });

    // 1. Add Query Node (column 0, centered vertically)
    const queryY = contentStartY + (maxTotalHeight - nodeHeight) / 2;
    nodes.push({
      id: 'query-node',
      type: 'query',
      position: { x: getColumnX(0) - 60, y: queryY }, // Assuming query node width ~120
      data: {
        label: data.query,
        isDark,
        fontSize: fontSize + 2,
      },
      draggable: false,
      selectable: false,
    });

    // 2. Add Category Headers (starting from column 1)
    sortedCategories.forEach((cat, colIndex) => {
      const columnX = getColumnX(colIndex + 1);
      nodes.push({
        id: `header-${cat.name}`,
        type: 'categoryHeader',
        position: { x: columnX - headerWidth / 2, y: 0 }, // Centered
        data: {
          label: cat.name,
          color: categoryColors[cat.name]?.fill || '#666',
          isFixed: cat.is_fixed,
          isDark,
        },
        draggable: false,
        selectable: false,
        zIndex: 10,
      });
    });

    // 3. Add Attribute Nodes
    sortedCategories.forEach((cat, colIndex) => {
      const categoryNodes = nodesByCategory[cat.name] || [];
      const columnX = getColumnX(colIndex + 1);

      categoryNodes.forEach((node, rowIndex) => {
        const y = contentStartY + rowIndex * (nodeHeight + nodeSpacing);
        nodes.push({
          id: node.id,
          type: 'attribute',
          position: { x: columnX - nodeWidth / 2, y }, // Centered
          data: {
            label: node.name,
            fillColor: categoryColors[node.category]?.fill || '#666',
            strokeColor: categoryColors[node.category]?.stroke || '#444',
            fontSize,
          },
          draggable: false,
          selectable: false,
          zIndex: 5,
        });
      });
    });

    return nodes;
  }, [data, config]);
}
