'use client';

import { useMemo } from 'react';
import { motion } from 'framer-motion';
import { cn } from '@/lib/utils';
import type { DecisionTreeState, DecisionNodeState } from '@/lib/visualizations/types';
import { DecisionNode } from '../primitives/decision-node';

interface DecisionTreeViewProps {
  tree: DecisionTreeState;
  className?: string;
}

const NODE_WIDTH = 64;
const NODE_HEIGHT = 32;
const LEVEL_HEIGHT = 80;
const MIN_NODE_SPACING = 72;
const SVG_PADDING = 40;

interface NodePosition {
  node: DecisionNodeState;
  x: number;
  y: number;
  parentX?: number;
  parentY?: number;
  isLeftChild?: boolean;
}

function buildNodeMap(nodes: DecisionNodeState[]): Map<string, DecisionNodeState> {
  const map = new Map<string, DecisionNodeState>();
  for (const node of nodes) {
    map.set(node.id, node);
  }
  return map;
}

function calculateTreeDepth(
  nodeId: string | null,
  nodeMap: Map<string, DecisionNodeState>
): number {
  if (!nodeId) return 0;
  const node = nodeMap.get(nodeId);
  if (!node) return 0;
  const leftDepth = calculateTreeDepth(node.left, nodeMap);
  const rightDepth = calculateTreeDepth(node.right, nodeMap);
  return 1 + Math.max(leftDepth, rightDepth);
}

function calculatePositions(
  tree: DecisionTreeState,
  totalWidth: number
): NodePosition[] {
  const nodeMap = buildNodeMap(tree.nodes);
  const positions: NodePosition[] = [];

  function traverse(
    nodeId: string | null,
    level: number,
    left: number,
    right: number,
    parentX?: number,
    parentY?: number,
    isLeftChild?: boolean
  ) {
    if (!nodeId) return;
    const node = nodeMap.get(nodeId);
    if (!node) return;

    const x = (left + right) / 2;
    const y = SVG_PADDING + level * LEVEL_HEIGHT + NODE_HEIGHT / 2;

    positions.push({ node, x, y, parentX, parentY, isLeftChild });

    const childWidth = (right - left) / 2;
    traverse(node.left, level + 1, left, left + childWidth, x, y, true);
    traverse(node.right, level + 1, left + childWidth, right, x, y, false);
  }

  traverse(tree.rootId, 0, 0, totalWidth);
  return positions;
}

export function DecisionTreeView({
  tree,
  className,
}: DecisionTreeViewProps) {
  const { positions, svgWidth, svgHeight } = useMemo(() => {
    const nodeMap = buildNodeMap(tree.nodes);
    const depth = calculateTreeDepth(tree.rootId, nodeMap);
    const maxNodesAtBottom = Math.pow(2, depth - 1);
    const width = Math.max(
      maxNodesAtBottom * MIN_NODE_SPACING + SVG_PADDING * 2,
      300
    );
    const height = depth * LEVEL_HEIGHT + SVG_PADDING * 2;
    const pos = calculatePositions(tree, width);
    return { positions: pos, svgWidth: width, svgHeight: height };
  }, [tree]);

  const currentPath = new Set(tree.currentPath ?? []);

  return (
    <div className={cn('flex flex-col items-center', className)}>
      {tree.label && (
        <span className="mb-2 text-sm font-medium text-[var(--muted-foreground)]">
          {tree.label}
        </span>
      )}
      <svg
        width={svgWidth}
        height={svgHeight}
        viewBox={`0 0 ${svgWidth} ${svgHeight}`}
        className="overflow-visible"
      >
        {/* Draw edges first (behind nodes) */}
        {positions.map(({ node, x, y, parentX, parentY, isLeftChild }) =>
          parentX !== undefined && parentY !== undefined ? (
            <g key={`edge-${node.id}`}>
              {/* Edge line */}
              <motion.line
                x1={parentX}
                y1={parentY + NODE_HEIGHT / 2}
                x2={x}
                y2={y - NODE_HEIGHT / 2}
                className={cn(
                  'stroke-[var(--border)]',
                  currentPath.has(node.id) && 'stroke-[var(--primary)]'
                )}
                strokeWidth={currentPath.has(node.id) ? 2.5 : 2}
                initial={false}
                animate={{
                  opacity: node.state === 'complete' ? 0.6 : 1,
                }}
                transition={{ duration: 0.2 }}
              />
              {/* Branch label */}
              <text
                x={(parentX + x) / 2 + (isLeftChild ? -8 : 8)}
                y={(parentY + NODE_HEIGHT / 2 + y - NODE_HEIGHT / 2) / 2}
                textAnchor="middle"
                dominantBaseline="central"
                className={cn(
                  'text-[10px] font-medium',
                  currentPath.has(node.id)
                    ? 'fill-[var(--primary)]'
                    : 'fill-[var(--muted-foreground)]'
                )}
              >
                {isLeftChild ? '+' : '−'}
              </text>
            </g>
          ) : null
        )}

        {/* Draw nodes */}
        {positions.map(({ node, x, y }) => (
          <DecisionNode
            key={node.id}
            node={node}
            x={x}
            y={y}
            width={NODE_WIDTH}
            height={NODE_HEIGHT}
            isInPath={currentPath.has(node.id)}
          />
        ))}
      </svg>
    </div>
  );
}
