import React, { useMemo } from 'react';
import { useGridStore } from '../../store/gridStore';
import type { ColoredPath } from '../../store/gridStore';
import { Map as MapIcon } from 'lucide-react';
import type { SearchStep } from '../../types';

const CELL_SIZE = 90;
const PADDING = 70;
const NODE_RADIUS = 14;

const COLORS = {
  background: '#0a0a0b',
  gridLine: '#1f1f23',

  // Node states
  nodeDefault: '#27272a',
  nodeDefaultStroke: '#3f3f46',
  frontier: '#0ea5e9',
  frontierLight: '#38bdf8',
  explored: '#52525b',
  exploredLight: '#71717a',
  current: '#f59e0b',
  currentLight: '#fbbf24',
  path: '#10b981',
  pathLight: '#34d399',

  // Entities
  store: '#3b82f6',
  storeLight: '#60a5fa',
  destination: '#10b981',
  destinationLight: '#34d399',
  tunnel: '#a855f7',
  tunnelLight: '#c084fc',

  // Edges
  edge1: '#a1a1aa',
  edge2: '#71717a',
  edge3: '#52525b',
  edge4: '#3f3f46',
  blocked: '#ef4444',
  blockedBg: '#450a0a',

  // Text
  text: '#fafafa',
  textMuted: '#a1a1aa',
  textDim: '#52525b',
};

export const Grid: React.FC = () => {
  const { grid, steps, currentStep, searchResult, showPlanPaths, planPaths } = useGridStore();

  const stepData = useMemo(() => {
    const step: SearchStep | null = steps[currentStep] || null;
    return {
      step,
      exploredSet: new Set(step?.explored.map(p => `${p.x},${p.y}`) || []),
      frontierSet: new Set(step?.frontier.map(p => `${p.x},${p.y}`) || []),
      pathSet: new Set(step?.currentPath.map(p => `${p.x},${p.y}`) || []),
      finalPathSet: new Set((searchResult?.path || []).map(p => `${p.x},${p.y}`)),
    };
  }, [steps, currentStep, searchResult]);

  // Build a map of position -> color for plan paths visualization
  const planPathData = useMemo(() => {
    if (!showPlanPaths || planPaths.length === 0) {
      return { pathColorMap: new Map<string, string>(), pathEdges: [] as { from: string; to: string; color: string }[] };
    }

    const pathColorMap = new Map<string, string>();
    const pathEdges: { from: string; to: string; color: string }[] = [];

    planPaths.forEach((coloredPath: ColoredPath) => {
      const path = coloredPath.path;
      for (let i = 0; i < path.length; i++) {
        const key = `${path[i].x},${path[i].y}`;
        // First path to claim a position gets to color it
        if (!pathColorMap.has(key)) {
          pathColorMap.set(key, coloredPath.color);
        }
        // Build edges
        if (i < path.length - 1) {
          const fromKey = `${path[i].x},${path[i].y}`;
          const toKey = `${path[i + 1].x},${path[i + 1].y}`;
          pathEdges.push({ from: fromKey, to: toKey, color: coloredPath.color });
        }
      }
    });

    return { pathColorMap, pathEdges };
  }, [showPlanPaths, planPaths]);

  if (!grid) {
    return (
      <div className="flex items-center justify-center h-full" style={{ backgroundColor: '#0a0a0b' }}>
        <div className="text-center">
          <div className="w-20 h-20 rounded-2xl bg-zinc-900 border border-zinc-800 flex items-center justify-center mx-auto mb-6">
            <MapIcon className="w-10 h-10 text-zinc-700" />
          </div>
          <p className="text-zinc-400 text-sm font-medium">No Grid Generated</p>
          <p className="text-zinc-600 text-xs mt-2">Configure and generate a grid from the sidebar</p>
        </div>
      </div>
    );
  }

  const width = grid.width * CELL_SIZE + PADDING * 2;
  const height = grid.height * CELL_SIZE + PADDING * 2;

  const { step, exploredSet, frontierSet, pathSet, finalPathSet } = stepData;
  const { pathColorMap, pathEdges } = planPathData;

  const getNodeState = (x: number, y: number): { state: string; color?: string } => {
    const key = `${x},${y}`;
    if (step?.currentNode.x === x && step?.currentNode.y === y) return { state: 'current' };
    if (pathSet.has(key) || (!step && finalPathSet.has(key))) return { state: 'path' };
    if (frontierSet.has(key)) return { state: 'frontier' };
    if (exploredSet.has(key)) return { state: 'explored' };
    // Check if this node is part of a plan path
    if (showPlanPaths && pathColorMap.has(key)) {
      return { state: 'planPath', color: pathColorMap.get(key) };
    }
    return { state: 'default' };
  };

  const getEdgeStyle = (traffic: number) => {
    if (traffic === 0) return { color: COLORS.blocked, width: 2, opacity: 0.4 };
    const colors = [COLORS.edge1, COLORS.edge2, COLORS.edge3, COLORS.edge4];
    const widths = [3, 2.5, 2, 1.5];
    return { color: colors[traffic - 1], width: widths[traffic - 1], opacity: 0.7 };
  };

  const toSvgY = (gridY: number) => PADDING + (grid.height - 1 - gridY) * CELL_SIZE + CELL_SIZE / 2;
  const toSvgX = (gridX: number) => PADDING + gridX * CELL_SIZE + CELL_SIZE / 2;

  return (
    <div className="w-full h-full flex items-center justify-center overflow-auto" style={{ backgroundColor: '#0a0a0b' }}>
      <svg
        width={width}
        height={height}
        viewBox={`0 0 ${width} ${height}`}
        style={{ minWidth: Math.min(width, 500), minHeight: Math.min(height, 400) }}
      >
        <defs>
          {/* Glows for different states */}
          <filter id="glow-current" x="-100%" y="-100%" width="300%" height="300%">
            <feGaussianBlur stdDeviation="6" result="blur"/>
            <feFlood floodColor={COLORS.current} result="color"/>
            <feComposite in="color" in2="blur" operator="in" result="glow"/>
            <feMerge>
              <feMergeNode in="glow"/>
              <feMergeNode in="glow"/>
              <feMergeNode in="SourceGraphic"/>
            </feMerge>
          </filter>

          <filter id="glow-path" x="-100%" y="-100%" width="300%" height="300%">
            <feGaussianBlur stdDeviation="4" result="blur"/>
            <feFlood floodColor={COLORS.path} result="color"/>
            <feComposite in="color" in2="blur" operator="in" result="glow"/>
            <feMerge>
              <feMergeNode in="glow"/>
              <feMergeNode in="SourceGraphic"/>
            </feMerge>
          </filter>

          <filter id="glow-frontier" x="-100%" y="-100%" width="300%" height="300%">
            <feGaussianBlur stdDeviation="3" result="blur"/>
            <feFlood floodColor={COLORS.frontier} result="color"/>
            <feComposite in="color" in2="blur" operator="in" result="glow"/>
            <feMerge>
              <feMergeNode in="glow"/>
              <feMergeNode in="SourceGraphic"/>
            </feMerge>
          </filter>

          <filter id="glow-tunnel" x="-100%" y="-100%" width="300%" height="300%">
            <feGaussianBlur stdDeviation="4" result="blur"/>
            <feFlood floodColor={COLORS.tunnel} result="color"/>
            <feComposite in="color" in2="blur" operator="in" result="glow"/>
            <feMerge>
              <feMergeNode in="glow"/>
              <feMergeNode in="SourceGraphic"/>
            </feMerge>
          </filter>

          {/* Tunnel gradient */}
          <linearGradient id="tunnel-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" stopColor={COLORS.tunnel} stopOpacity="0.3"/>
            <stop offset="50%" stopColor={COLORS.tunnelLight} stopOpacity="0.6"/>
            <stop offset="100%" stopColor={COLORS.tunnel} stopOpacity="0.3"/>
          </linearGradient>

          {/* Blocked pattern */}
          <pattern id="blocked-hatch" patternUnits="userSpaceOnUse" width="6" height="6" patternTransform="rotate(45)">
            <line x1="0" y1="0" x2="0" y2="6" stroke={COLORS.blocked} strokeWidth="1" opacity="0.3"/>
          </pattern>
        </defs>

        {/* Background */}
        <rect x={0} y={0} width={width} height={height} fill={COLORS.background} rx={8}/>

        {/* Grid cells background */}
        {Array.from({ length: grid.width }).map((_, x) =>
          Array.from({ length: grid.height }).map((_, y) => (
            <rect
              key={`cell-bg-${x}-${y}`}
              x={PADDING + x * CELL_SIZE + 2}
              y={PADDING + (grid.height - 1 - y) * CELL_SIZE + 2}
              width={CELL_SIZE - 4}
              height={CELL_SIZE - 4}
              fill={COLORS.gridLine}
              opacity={0.3}
              rx={4}
            />
          ))
        )}

        {/* Edges */}
        {grid.segments.map((segment, i) => {
          const x1 = toSvgX(segment.src.x);
          const y1 = toSvgY(segment.src.y);
          const x2 = toSvgX(segment.dst.x);
          const y2 = toSvgY(segment.dst.y);
          const midX = (x1 + x2) / 2;
          const midY = (y1 + y2) / 2;
          const isBlocked = segment.traffic === 0;
          const style = getEdgeStyle(segment.traffic);

          if (isBlocked) {
            return (
              <g key={`seg-${i}`}>
                {/* Blocked edge line */}
                <line
                  x1={x1} y1={y1} x2={x2} y2={y2}
                  stroke={COLORS.blocked}
                  strokeWidth={2}
                  strokeDasharray="8,6"
                  opacity={0.25}
                />
                {/* Blocked indicator */}
                <g transform={`translate(${midX}, ${midY})`}>
                  <circle r={14} fill={COLORS.blockedBg} stroke={COLORS.blocked} strokeWidth={1.5} opacity={0.9}/>
                  <line x1={-5} y1={-5} x2={5} y2={5} stroke={COLORS.blocked} strokeWidth={2} strokeLinecap="round"/>
                  <line x1={5} y1={-5} x2={-5} y2={5} stroke={COLORS.blocked} strokeWidth={2} strokeLinecap="round"/>
                </g>
              </g>
            );
          }

          return (
            <g key={`seg-${i}`}>
              {/* Edge line */}
              <line
                x1={x1} y1={y1} x2={x2} y2={y2}
                stroke={style.color}
                strokeWidth={style.width}
                strokeLinecap="round"
                opacity={style.opacity}
              />
              {/* Cost badge */}
              <g transform={`translate(${midX}, ${midY})`}>
                <rect
                  x={-10} y={-10}
                  width={20} height={20}
                  fill={COLORS.background}
                  stroke={style.color}
                  strokeWidth={1}
                  rx={4}
                  opacity={0.95}
                />
                <text
                  textAnchor="middle"
                  dominantBaseline="middle"
                  fill={style.color}
                  fontSize={11}
                  fontWeight="600"
                  fontFamily="ui-monospace, monospace"
                >
                  {segment.traffic}
                </text>
              </g>
            </g>
          );
        })}

        {/* Tunnels */}
        {grid.tunnels.map((tunnel, i) => {
          const x1 = toSvgX(tunnel.entrance1.x);
          const y1 = toSvgY(tunnel.entrance1.y);
          const x2 = toSvgX(tunnel.entrance2.x);
          const y2 = toSvgY(tunnel.entrance2.y);
          const midX = (x1 + x2) / 2;
          const midY = (y1 + y2) / 2;
          const dx = x2 - x1;
          const dy = y2 - y1;
          const len = Math.sqrt(dx * dx + dy * dy);
          const curveOffset = Math.min(60, len / 2.5);
          const perpX = -dy / len * curveOffset;
          const perpY = dx / len * curveOffset;

          return (
            <g key={`tunnel-${i}`}>
              {/* Tunnel glow background */}
              <path
                d={`M ${x1} ${y1} Q ${midX + perpX} ${midY + perpY} ${x2} ${y2}`}
                stroke={COLORS.tunnelLight}
                strokeWidth={12}
                fill="none"
                opacity={0.15}
                strokeLinecap="round"
              />
              {/* Tunnel path */}
              <path
                d={`M ${x1} ${y1} Q ${midX + perpX} ${midY + perpY} ${x2} ${y2}`}
                stroke="url(#tunnel-gradient)"
                strokeWidth={4}
                fill="none"
                strokeLinecap="round"
              />
              {/* Animated dashes */}
              <path
                d={`M ${x1} ${y1} Q ${midX + perpX} ${midY + perpY} ${x2} ${y2}`}
                stroke={COLORS.tunnel}
                strokeWidth={2}
                strokeDasharray="4,8"
                fill="none"
                opacity={0.8}
                strokeLinecap="round"
              >
                <animate
                  attributeName="stroke-dashoffset"
                  from="0"
                  to="24"
                  dur="1.5s"
                  repeatCount="indefinite"
                />
              </path>

              {/* Portal entrance 1 */}
              <g transform={`translate(${x1}, ${y1})`} filter="url(#glow-tunnel)">
                <circle r={16} fill={COLORS.background} stroke={COLORS.tunnel} strokeWidth={2}/>
                <circle r={10} fill={COLORS.tunnel} opacity={0.3}/>
                <circle r={5} fill={COLORS.tunnelLight}/>
              </g>

              {/* Portal entrance 2 */}
              <g transform={`translate(${x2}, ${y2})`} filter="url(#glow-tunnel)">
                <circle r={16} fill={COLORS.background} stroke={COLORS.tunnel} strokeWidth={2}/>
                <circle r={10} fill={COLORS.tunnel} opacity={0.3}/>
                <circle r={5} fill={COLORS.tunnelLight}/>
              </g>

              {/* Cost label */}
              <g transform={`translate(${midX + perpX * 0.6}, ${midY + perpY * 0.6})`}>
                <rect
                  x={-18} y={-11}
                  width={36} height={22}
                  fill={COLORS.background}
                  stroke={COLORS.tunnel}
                  strokeWidth={1.5}
                  rx={6}
                />
                <text
                  textAnchor="middle"
                  dominantBaseline="middle"
                  fill={COLORS.tunnelLight}
                  fontSize={11}
                  fontWeight="600"
                  fontFamily="ui-monospace, monospace"
                >
                  T:{tunnel.cost}
                </text>
              </g>
            </g>
          );
        })}

        {/* Plan Path Edges (rendered before nodes) */}
        {showPlanPaths && pathEdges.map((edge, i) => {
          const [fromX, fromY] = edge.from.split(',').map(Number);
          const [toX, toY] = edge.to.split(',').map(Number);
          const x1 = toSvgX(fromX);
          const y1 = toSvgY(fromY);
          const x2 = toSvgX(toX);
          const y2 = toSvgY(toY);

          return (
            <line
              key={`plan-edge-${i}`}
              x1={x1} y1={y1} x2={x2} y2={y2}
              stroke={edge.color}
              strokeWidth={5}
              strokeLinecap="round"
              opacity={0.8}
            />
          );
        })}

        {/* Nodes */}
        {Array.from({ length: grid.width }).map((_, x) =>
          Array.from({ length: grid.height }).map((_, y) => {
            const cx = toSvgX(x);
            const cy = toSvgY(y);
            const nodeState = getNodeState(x, y);
            const state = nodeState.state;

            let fill = COLORS.nodeDefault;
            let stroke = COLORS.nodeDefaultStroke;
            let filter = '';
            let radius = NODE_RADIUS;
            let strokeWidth = 1.5;

            switch (state) {
              case 'current':
                fill = COLORS.current;
                stroke = COLORS.currentLight;
                filter = 'url(#glow-current)';
                radius = NODE_RADIUS + 2;
                strokeWidth = 2;
                break;
              case 'path':
                fill = COLORS.path;
                stroke = COLORS.pathLight;
                filter = 'url(#glow-path)';
                strokeWidth = 2;
                break;
              case 'frontier':
                fill = COLORS.frontier;
                stroke = COLORS.frontierLight;
                filter = 'url(#glow-frontier)';
                break;
              case 'explored':
                fill = COLORS.explored;
                stroke = COLORS.exploredLight;
                break;
              case 'planPath':
                fill = nodeState.color || COLORS.path;
                stroke = nodeState.color || COLORS.pathLight;
                strokeWidth = 2;
                break;
            }

            return (
              <g key={`node-${x}-${y}`}>
                <circle
                  cx={cx}
                  cy={cy}
                  r={radius}
                  fill={fill}
                  stroke={stroke}
                  strokeWidth={strokeWidth}
                  filter={filter}
                  opacity={state === 'default' ? 0.4 : 1}
                  style={{ transition: 'all 0.15s ease-out' }}
                />
                {state === 'current' && (
                  <circle
                    cx={cx}
                    cy={cy}
                    r={radius + 6}
                    fill="none"
                    stroke={COLORS.current}
                    strokeWidth={1.5}
                    opacity={0.4}
                  >
                    <animate
                      attributeName="r"
                      from={radius + 4}
                      to={radius + 12}
                      dur="1s"
                      repeatCount="indefinite"
                    />
                    <animate
                      attributeName="opacity"
                      from="0.5"
                      to="0"
                      dur="1s"
                      repeatCount="indefinite"
                    />
                  </circle>
                )}
              </g>
            );
          })
        )}

        {/* Stores */}
        {grid.stores.map((store) => {
          const cx = toSvgX(store.position.x);
          const cy = toSvgY(store.position.y);

          return (
            <g key={`store-${store.id}`}>
              <rect
                x={cx - 18}
                y={cy - 18}
                width={36}
                height={36}
                fill={COLORS.store}
                stroke={COLORS.storeLight}
                strokeWidth={2}
                rx={8}
              />
              <rect
                x={cx - 12}
                y={cy - 6}
                width={24}
                height={4}
                fill={COLORS.storeLight}
                rx={2}
              />
              <text
                x={cx}
                y={cy + 8}
                textAnchor="middle"
                dominantBaseline="middle"
                fill={COLORS.text}
                fontSize={11}
                fontWeight="700"
                fontFamily="ui-monospace, monospace"
              >
                S{store.id}
              </text>
            </g>
          );
        })}

        {/* Destinations */}
        {grid.destinations.map((dest) => {
          const cx = toSvgX(dest.position.x);
          const cy = toSvgY(dest.position.y);

          return (
            <g key={`dest-${dest.id}`}>
              <circle
                cx={cx}
                cy={cy}
                r={18}
                fill={COLORS.destination}
                stroke={COLORS.destinationLight}
                strokeWidth={2}
              />
              {/* Target rings */}
              <circle cx={cx} cy={cy} r={12} fill="none" stroke={COLORS.destinationLight} strokeWidth={1.5} opacity={0.5}/>
              <circle cx={cx} cy={cy} r={6} fill={COLORS.destinationLight} opacity={0.8}/>
              <text
                x={cx}
                y={cy + 28}
                textAnchor="middle"
                fill={COLORS.textMuted}
                fontSize={10}
                fontWeight="600"
                fontFamily="ui-monospace, monospace"
              >
                D{dest.id}
              </text>
            </g>
          );
        })}

        {/* Axis labels */}
        {Array.from({ length: grid.width }).map((_, x) => (
          <text
            key={`x-${x}`}
            x={toSvgX(x)}
            y={height - 25}
            textAnchor="middle"
            fontSize={11}
            fill={COLORS.textDim}
            fontFamily="ui-monospace, monospace"
            fontWeight="500"
          >
            {x}
          </text>
        ))}
        {Array.from({ length: grid.height }).map((_, y) => (
          <text
            key={`y-${y}`}
            x={25}
            y={toSvgY(y) + 4}
            textAnchor="middle"
            fontSize={11}
            fill={COLORS.textDim}
            fontFamily="ui-monospace, monospace"
            fontWeight="500"
          >
            {y}
          </text>
        ))}
      </svg>
    </div>
  );
};

export default Grid;
