import { useEffect, useRef } from "react";
import type { Detection } from "../hooks/LLMContext";
import { toPixelCoords, DETECTION_COLORS } from "../utils/detection-parser";

interface DetectionOverlayProps {
  imageUrl: string;
  detections: Detection[];
}

export function DetectionOverlay({ imageUrl, detections }: DetectionOverlayProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const imgRef = useRef<HTMLImageElement>(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    const img = imgRef.current;
    if (!canvas || !img || !img.complete) return;

    const ctx = canvas.getContext("2d");
    if (!ctx) return;

    // Match canvas size to displayed image size
    const rect = img.getBoundingClientRect();
    canvas.width = rect.width;
    canvas.height = rect.height;

    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Build unique label map for consistent colors
    const labelSet = [...new Set(detections.map((d) => d.label))];

    for (const det of detections) {
      const [x1, y1, x2, y2] = toPixelCoords(
        det.box_2d,
        canvas.width,
        canvas.height,
      );
      const colorIdx = labelSet.indexOf(det.label);
      const color = DETECTION_COLORS[colorIdx % DETECTION_COLORS.length];

      // Draw box
      ctx.strokeStyle = color;
      ctx.lineWidth = 2.5;
      ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);

      // Draw label background
      ctx.font = "bold 13px 'Google Sans', sans-serif";
      const textWidth = ctx.measureText(det.label).width;
      const labelHeight = 20;
      const labelY = Math.max(0, y1 - labelHeight);

      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.roundRect(x1, labelY, textWidth + 10, labelHeight, 4);
      ctx.fill();

      // Draw label text
      ctx.fillStyle = "#ffffff";
      ctx.fillText(det.label, x1 + 5, labelY + 14);
    }
  }, [detections]);

  const handleImageLoad = () => {
    // Re-trigger detection rendering once image loads
    if (detections.length > 0) {
      const canvas = canvasRef.current;
      const img = imgRef.current;
      if (!canvas || !img) return;

      const ctx = canvas.getContext("2d");
      if (!ctx) return;

      const rect = img.getBoundingClientRect();
      canvas.width = rect.width;
      canvas.height = rect.height;

      ctx.clearRect(0, 0, canvas.width, canvas.height);

      const labelSet = [...new Set(detections.map((d) => d.label))];

      for (const det of detections) {
        const [x1, y1, x2, y2] = toPixelCoords(
          det.box_2d,
          canvas.width,
          canvas.height,
        );
        const colorIdx = labelSet.indexOf(det.label);
        const color = DETECTION_COLORS[colorIdx % DETECTION_COLORS.length];

        ctx.strokeStyle = color;
        ctx.lineWidth = 2.5;
        ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);

        ctx.font = "bold 13px 'Google Sans', sans-serif";
        const textWidth = ctx.measureText(det.label).width;
        const labelHeight = 20;
        const labelY = Math.max(0, y1 - labelHeight);

        ctx.fillStyle = color;
        ctx.beginPath();
        ctx.roundRect(x1, labelY, textWidth + 10, labelHeight, 4);
        ctx.fill();

        ctx.fillStyle = "#ffffff";
        ctx.fillText(det.label, x1 + 5, labelY + 14);
      }
    }
  };

  return (
    <div className="relative inline-block w-full">
      <img
        ref={imgRef}
        src={imageUrl}
        alt="Detection result"
        className="w-full max-h-[500px] object-contain rounded-xl"
        onLoad={handleImageLoad}
      />
      <canvas
        ref={canvasRef}
        className="absolute top-0 left-0 w-full h-full pointer-events-none"
        style={{ objectFit: "contain" }}
      />
    </div>
  );
}
