"use client";

import React, { useEffect, useRef, useState, useCallback } from "react";
import { cn } from "@/lib/utils";

type Point = { x: number; y: number };

const WhiteboardCanvas = () => {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
  const ctxRef = useRef<CanvasRenderingContext2D | null>(null);
  const [isDrawing, setIsDrawing] = useState(false);
  const [lastPoint, setLastPoint] = useState<Point | null>(null);
  const [strokeColor, setStrokeColor] = useState<string>("#111111");
  const [strokeWidth, setStrokeWidth] = useState<number>(3);

  // Setup canvas with proper DPR scaling
  const resizeCanvas = useCallback(() => {
    const canvas = canvasRef.current;
    const container = containerRef.current;
    if (!canvas || !container) return;

    const dpr = window.devicePixelRatio || 1;
    const rect = container.getBoundingClientRect();

    canvas.width = Math.max(320, Math.floor(rect.width * dpr));
    canvas.height = Math.max(320, Math.floor((rect.height - 60) * dpr)); // minus controls height
    canvas.style.width = `${Math.floor(canvas.width / dpr)}px`;
    canvas.style.height = `${Math.floor(canvas.height / dpr)}px`;

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

    ctxRef.current = ctx;

    // When resizing, keep existing content by redrawing the bitmap:
    // Create a temp bitmap from existing content before resizing (if any).
    // Note: For simplicity, we won't preserve content across resizes in this minimal version.
    // Initialize canvas background as transparent. Users can export PNG.
    ctx.lineCap = "round";
    ctx.lineJoin = "round";
  }, []);

  useEffect(() => {
    resizeCanvas();
    const onResize = () => resizeCanvas();
    window.addEventListener("resize", onResize);

    // If container changes size (e.g., sheet opening), observe it
    const ro = new ResizeObserver(() => resizeCanvas());
    if (containerRef.current) {
      ro.observe(containerRef.current);
    }

    return () => {
      window.removeEventListener("resize", onResize);
      ro.disconnect();
    };
  }, [resizeCanvas]);

  const getRelativePoint = (e: PointerEvent | React.PointerEvent<HTMLCanvasElement>): Point => {
    const canvas = canvasRef.current!;
    const rect = canvas.getBoundingClientRect();
    const dpr = window.devicePixelRatio || 1;
    const x = (e.clientX - rect.left) * dpr;
    const y = (e.clientY - rect.top) * dpr;
    return { x, y };
  };

  const handlePointerDown = (e: React.PointerEvent<HTMLCanvasElement>) => {
    e.currentTarget.setPointerCapture(e.pointerId);
    setIsDrawing(true);
    const p = getRelativePoint(e);
    setLastPoint(p);
  };

  const handlePointerMove = (e: React.PointerEvent<HTMLCanvasElement>) => {
    if (!isDrawing || !lastPoint || !ctxRef.current) return;
    const p = getRelativePoint(e);
    const ctx = ctxRef.current;
    ctx.strokeStyle = strokeColor;
    const dpr = window.devicePixelRatio || 1;
    ctx.lineWidth = Math.max(1, strokeWidth * dpr);

    ctx.beginPath();
    ctx.moveTo(lastPoint.x, lastPoint.y);
    ctx.lineTo(p.x, p.y);
    ctx.stroke();
    setLastPoint(p);
  };

  const handlePointerUp = (e: React.PointerEvent<HTMLCanvasElement>) => {
    if (e.currentTarget.hasPointerCapture(e.pointerId)) {
      e.currentTarget.releasePointerCapture(e.pointerId);
    }
    setIsDrawing(false);
    setLastPoint(null);
  };

  const handlePointerLeave = () => {
    setIsDrawing(false);
    setLastPoint(null);
  };

  const handleClear = () => {
    const canvas = canvasRef.current;
    const ctx = ctxRef.current;
    if (!canvas || !ctx) return;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  };

  const handleDownload = () => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const link = document.createElement("a");
    link.download = "whiteboard.png";
    link.href = canvas.toDataURL("image/png");
    link.click();
  };

  return (
    <div ref={containerRef} className="w-full h-[70vh] min-h-[360px]">
      <div className="flex items-center gap-2 pb-3">
        <label className="text-sm" htmlFor="stroke-color">
          Color
        </label>
        <input
          id="stroke-color"
          aria-label="Stroke color"
          type="color"
          value={strokeColor}
          onChange={(e) => setStrokeColor(e.target.value)}
          className="h-8 w-10 rounded border border-black/10 dark:border-white/10 bg-transparent"
        />
        <label className="text-sm pl-2" htmlFor="stroke-width">
          Size
        </label>
        <input
          id="stroke-width"
          aria-label="Stroke width"
          type="range"
          min={1}
          max={20}
          value={strokeWidth}
          onChange={(e) => setStrokeWidth(Number(e.target.value))}
          className="w-32 accent-[color:var(--accent)]"
        />
        <button
          type="button"
          onClick={handleClear}
          className={cn(
            "px-3 py-1.5 text-sm rounded-md transition-colors",
            "bg-black/80 text-white hover:bg-black",
            "dark:bg-white/10 dark:text-white dark:hover:bg-white/20"
          )}
          aria-label="Clear canvas"
        >
          Clear
        </button>
        <button
          type="button"
          onClick={handleDownload}
          className={cn(
            "px-3 py-1.5 text-sm rounded-md transition-colors",
            "bg-[color:var(--accent)] text-black hover:brightness-110"
          )}
          aria-label="Download image"
        >
          Download
        </button>
      </div>

      <canvas
        ref={canvasRef}
        className={cn(
          "w-full h-[calc(70vh-3rem)] min-h-[300px] rounded-md",
          "bg-white dark:bg-neutral-900 border border-black/10 dark:border-white/10 touch-none"
        )}
        role="img"
        aria-label="Whiteboard drawing area"
        onPointerDown={handlePointerDown}
        onPointerMove={handlePointerMove}
        onPointerUp={handlePointerUp}
        onPointerLeave={handlePointerLeave}
      />
    </div>
  );
};

export default WhiteboardCanvas;
