"use client";

import { useMemo } from "react";
import type { HistogramState, ElementState } from "@/types/visualization";

interface HistogramVisualizerProps {
  data: HistogramState;
  name?: string;
}

const BAR_WIDTH = 48;
const BAR_GAP = 4;
const MAX_BAR_HEIGHT = 180;
const INDEX_AREA_HEIGHT = 20;
const POINTER_HEIGHT = 24;
const ANNOTATION_HEIGHT = 20;
const AREA_LABEL_HEIGHT = 24;
const SVG_PADDING = 16;

function getStateColor(state: ElementState): string {
  switch (state) {
    case "active":
      return "var(--viz-active)";
    case "comparing":
      return "var(--viz-comparing)";
    case "found":
      return "var(--viz-found)";
    case "visited":
      return "var(--viz-visited)";
    case "swapping":
      return "var(--viz-swapping)";
    default:
      return "var(--viz-default)";
  }
}

function getTextColor(state: ElementState): string {
  switch (state) {
    case "active":
    case "found":
    case "swapping":
      return "white";
    case "comparing":
      return "var(--foreground)";
    case "visited":
      return "var(--muted-foreground)";
    default:
      return "var(--foreground)";
  }
}

export function HistogramVisualizer({ data, name }: HistogramVisualizerProps) {
  const { bars, rectangle, pointers = {}, maxArea } = data;

  const dimensions = useMemo(() => {
    const hasPointers = Object.keys(pointers).length > 0;
    const hasAnnotations = bars.some(
      (b) => b.annotations && b.annotations.length > 0
    );
    const hasRectangle = !!rectangle;

    // Find max value to scale bars
    const maxValue = Math.max(...bars.map((b) => b.value), 1);

    const contentWidth = bars.length * BAR_WIDTH + (bars.length - 1) * BAR_GAP;
    const width = contentWidth + SVG_PADDING * 2;

    // Calculate height
    let height = MAX_BAR_HEIGHT + INDEX_AREA_HEIGHT + SVG_PADDING * 2;
    if (hasPointers) height += POINTER_HEIGHT + 8;
    if (hasAnnotations) height += ANNOTATION_HEIGHT;
    if (hasRectangle) height += AREA_LABEL_HEIGHT;

    // Calculate where bars start (from bottom, going up)
    const barBaseY = hasAnnotations
      ? SVG_PADDING + ANNOTATION_HEIGHT + MAX_BAR_HEIGHT
      : SVG_PADDING + MAX_BAR_HEIGHT;

    return {
      width,
      height,
      contentWidth,
      maxValue,
      hasPointers,
      hasAnnotations,
      hasRectangle,
      startX: SVG_PADDING,
      barBaseY,
    };
  }, [bars, pointers, rectangle]);

  // Group pointers by position for stacking
  const pointersByPosition = useMemo(() => {
    const grouped: Record<number, string[]> = {};
    for (const [label, index] of Object.entries(pointers)) {
      if (!grouped[index]) {
        grouped[index] = [];
      }
      grouped[index].push(label);
    }
    return grouped;
  }, [pointers]);

  // Calculate bar height from value
  const getBarHeight = (value: number): number => {
    return (value / dimensions.maxValue) * MAX_BAR_HEIGHT;
  };

  return (
    <div className="flex flex-col gap-2">
      {name && (
        <span className="text-sm font-medium text-muted-foreground">
          {name}
        </span>
      )}
      <div className="overflow-x-auto">
        <svg
          width={dimensions.width}
          height={dimensions.height}
          viewBox={`0 0 ${dimensions.width} ${dimensions.height}`}
          className="viz-histogram"
          role="img"
          aria-label={`Histogram visualization with ${bars.length} bars`}
        >
          {/* Rectangle overlay (rendered behind bars) */}
          {rectangle && (
            <g className="viz-rectangle">
              {/* Semi-transparent rectangle */}
              <rect
                x={
                  dimensions.startX +
                  rectangle.startIndex * (BAR_WIDTH + BAR_GAP)
                }
                y={
                  dimensions.barBaseY -
                  getBarHeight(rectangle.height)
                }
                width={
                  (rectangle.endIndex - rectangle.startIndex + 1) * BAR_WIDTH +
                  (rectangle.endIndex - rectangle.startIndex) * BAR_GAP
                }
                height={getBarHeight(rectangle.height)}
                fill={
                  rectangle.state === "found"
                    ? "var(--viz-found)"
                    : "var(--viz-comparing)"
                }
                opacity={0.3}
                rx={4}
              />
              {/* Rectangle border */}
              <rect
                x={
                  dimensions.startX +
                  rectangle.startIndex * (BAR_WIDTH + BAR_GAP)
                }
                y={
                  dimensions.barBaseY -
                  getBarHeight(rectangle.height)
                }
                width={
                  (rectangle.endIndex - rectangle.startIndex + 1) * BAR_WIDTH +
                  (rectangle.endIndex - rectangle.startIndex) * BAR_GAP
                }
                height={getBarHeight(rectangle.height)}
                fill="none"
                stroke={
                  rectangle.state === "found"
                    ? "var(--viz-found)"
                    : "var(--viz-comparing)"
                }
                strokeWidth={2}
                strokeDasharray={rectangle.state === "found" ? "none" : "4 2"}
                rx={4}
              />
              {/* Area label - positioned inside the rectangle */}
              {rectangle.label && (
                <text
                  x={
                    dimensions.startX +
                    rectangle.startIndex * (BAR_WIDTH + BAR_GAP) +
                    ((rectangle.endIndex - rectangle.startIndex + 1) *
                      BAR_WIDTH +
                      (rectangle.endIndex - rectangle.startIndex) * BAR_GAP) /
                      2
                  }
                  y={
                    dimensions.barBaseY -
                    getBarHeight(rectangle.height) / 2
                  }
                  textAnchor="middle"
                  dominantBaseline="middle"
                  fill="white"
                  fontSize={14}
                  fontWeight={700}
                  fontFamily="var(--font-mono, monospace)"
                  style={{ textShadow: "0 1px 2px rgba(0,0,0,0.8)" }}
                >
                  {rectangle.label}
                </text>
              )}
            </g>
          )}

          {/* Histogram bars */}
          <g>
            {bars.map((bar, index) => {
              const x = dimensions.startX + index * (BAR_WIDTH + BAR_GAP);
              const barHeight = getBarHeight(bar.value);
              const y = dimensions.barBaseY - barHeight;

              return (
                <g
                  key={index}
                  className="viz-element"
                  data-state={bar.state}
                >
                  {/* Bar background */}
                  <rect
                    x={x}
                    y={y}
                    width={BAR_WIDTH}
                    height={barHeight}
                    rx={4}
                    fill={getStateColor(bar.state)}
                    className="viz-bar-bg"
                  />

                  {/* Bar border */}
                  <rect
                    x={x}
                    y={y}
                    width={BAR_WIDTH}
                    height={barHeight}
                    rx={4}
                    fill="none"
                    stroke="var(--border)"
                    strokeWidth={1}
                  />

                  {/* Value label (inside bar or above if too short) */}
                  <text
                    x={x + BAR_WIDTH / 2}
                    y={barHeight > 30 ? y + 20 : y - 6}
                    textAnchor="middle"
                    dominantBaseline="middle"
                    className="viz-value"
                    fill={barHeight > 30 ? getTextColor(bar.state) : "var(--foreground)"}
                    fontSize={14}
                    fontWeight={500}
                    fontFamily="var(--font-mono, monospace)"
                  >
                    {bar.value}
                  </text>

                  {/* Annotations (above bar) */}
                  {bar.annotations && bar.annotations.length > 0 && (
                    <text
                      x={x + BAR_WIDTH / 2}
                      y={dimensions.barBaseY - MAX_BAR_HEIGHT - 8}
                      textAnchor="middle"
                      className="viz-annotation"
                      fill="var(--primary)"
                      fontSize={12}
                      fontWeight={600}
                    >
                      {bar.annotations.join(", ")}
                    </text>
                  )}
                </g>
              );
            })}
          </g>

          {/* Baseline */}
          <line
            x1={dimensions.startX - 4}
            y1={dimensions.barBaseY}
            x2={dimensions.startX + dimensions.contentWidth + 4}
            y2={dimensions.barBaseY}
            stroke="var(--border)"
            strokeWidth={2}
          />

          {/* Pointers (below baseline) */}
          {dimensions.hasPointers && (
            <g className="viz-pointers">
              {Object.entries(pointersByPosition).map(([posStr, labels]) => {
                const position = parseInt(posStr, 10);
                if (position < 0 || position >= bars.length) return null;

                const x =
                  dimensions.startX +
                  position * (BAR_WIDTH + BAR_GAP) +
                  BAR_WIDTH / 2;
                const y =
                  dimensions.barBaseY + INDEX_AREA_HEIGHT + POINTER_HEIGHT;

                return (
                  <g key={posStr} className="viz-pointer">
                    {/* Arrow */}
                    <line
                      x1={x}
                      y1={y}
                      x2={x}
                      y2={y - 10}
                      stroke="var(--primary)"
                      strokeWidth={2}
                      markerEnd="url(#histogram-arrowhead)"
                    />

                    {/* Label(s) */}
                    <text
                      x={x}
                      y={y + 12}
                      textAnchor="middle"
                      fill="var(--primary)"
                      fontSize={12}
                      fontWeight={600}
                      fontFamily="var(--font-mono, monospace)"
                    >
                      {labels.join(", ")}
                    </text>
                  </g>
                );
              })}
            </g>
          )}

          {/* Index labels */}
          <g className="viz-indices">
            {bars.map((_, index) => {
              const x = dimensions.startX + index * (BAR_WIDTH + BAR_GAP);

              return (
                <text
                  key={index}
                  x={x + BAR_WIDTH / 2}
                  y={dimensions.barBaseY + INDEX_AREA_HEIGHT / 2 + 4}
                  textAnchor="middle"
                  dominantBaseline="middle"
                  className="viz-index"
                  fill="var(--muted-foreground)"
                  fontSize={11}
                >
                  {index}
                </text>
              );
            })}
          </g>

          {/* Max area display */}
          {maxArea !== undefined && (
            <text
              x={dimensions.width - SVG_PADDING}
              y={SVG_PADDING + 12}
              textAnchor="end"
              fill="var(--primary)"
              fontSize={14}
              fontWeight={600}
              fontFamily="var(--font-mono, monospace)"
            >
              Max Area: {maxArea}
            </text>
          )}

          {/* Arrow marker definition */}
          <defs>
            <marker
              id="histogram-arrowhead"
              markerWidth="8"
              markerHeight="6"
              refX="0"
              refY="3"
              orient="auto"
            >
              <polygon points="0 0, 8 3, 0 6" fill="var(--primary)" />
            </marker>
          </defs>
        </svg>
      </div>
    </div>
  );
}
