// ─────────────────────────────────────────────────────────────────────────────
// Ultra Image Cropper 2.0 — Canvas Area (centre zone)
// Editable canvas with crop handles, zoom, pan, grid overlay
// ─────────────────────────────────────────────────────────────────────────────

import React, { useRef, useEffect, useCallback } from 'react';
import type { UltraContext } from '@/types';
import { useCanvasStore } from '@/store';
import { useCanvas } from '@/hooks/useCanvas';
import { CropOverlay } from '../tools/CropOverlay';
import { GridOverlayRenderer } from '../tools/GridOverlayRenderer';
import { TextLayerOverlay } from '../tools/TextLayerOverlay';

interface CanvasAreaProps {
  context: UltraContext;
  minWidth: number;
}

export const CanvasArea: React.FC<CanvasAreaProps> = ({ context, minWidth }) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const { initCanvas, startDraw, drawTo, commitDraw } = useCanvas();
  const {
    activeTool,
    zoom,
    setZoom,
    setPan,
    panX,
    panY,
    gridOverlay,
    imageWidth,
    imageHeight,
    canvasWidth,
    canvasHeight,
    sourceImage,
  } = useCanvasStore();

  // Current working dimensions — canvasWidth/Height update after crop/rotate/resize;
  // fall back to imageWidth/Height on initial load before the engine sets them.
  const currentW = canvasWidth  > 0 ? canvasWidth  : imageWidth;
  const currentH = canvasHeight > 0 ? canvasHeight : imageHeight;

  // ── Init canvas engine ────────────────────────────────────────────────────────
  useEffect(() => {
    initCanvas(canvasRef.current);
    return () => initCanvas(null);
  }, [initCanvas]);

  // ── Fit canvas to container whenever its pixel dimensions change ──────────────
  // Fires on: new image load, crop applied, rotate (90°), resize applied.
  useEffect(() => {
    if (!containerRef.current || !currentW || !currentH) return;
    const { clientWidth, clientHeight } = containerRef.current;
    const fitZoom = Math.min(
      (clientWidth - 80) / currentW,
      (clientHeight - 80) / currentH,
      1
    );
    setZoom(fitZoom);
    setPan(0, 0);
  }, [currentW, currentH, sourceImage, setZoom, setPan]);

  // ── Mouse wheel zoom ──────────────────────────────────────────────────────────
  // Keep current zoom in a ref so the wheel handler never needs `zoom` in its
  // dependency array — avoids recreating the callback on every zoom step.
  const zoomRef = useRef(zoom);
  useEffect(() => { zoomRef.current = zoom; }, [zoom]);

  const handleWheel = useCallback((e: WheelEvent) => {
    e.preventDefault();
    const delta = e.deltaY < 0 ? 1.1 : 0.9;
    setZoom(zoomRef.current * delta);
  }, [setZoom]);

  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    el.addEventListener('wheel', handleWheel, { passive: false });
    return () => el.removeEventListener('wheel', handleWheel);
  }, [handleWheel]);

  // ── Canvas drag pan (when not in crop mode) ────────────────────────────────────
  const isDragging = useRef(false);
  const dragStart = useRef({ x: 0, y: 0, panX: 0, panY: 0 });

  // RAF throttle: skip intermediate mouse-move events; always use the latest delta.
  const rafRef = useRef<number | null>(null);
  const latestDelta = useRef({ dx: 0, dy: 0 });

  useEffect(() => () => {
    if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
  }, []);

  // Convert mouse event to canvas pixel coordinates
  const toCanvasCoords = useCallback((e: React.MouseEvent): { x: number; y: number } | null => {
    const canvas = canvasRef.current;
    if (!canvas) return null;
    const rect = canvas.getBoundingClientRect();
    return {
      x: (e.clientX - rect.left) * (canvas.width / rect.width),
      y: (e.clientY - rect.top) * (canvas.height / rect.height),
    };
  }, []);

  const handleMouseDown = useCallback((e: React.MouseEvent) => {
    if (activeTool === 'crop') return;
    if (activeTool === 'draw') {
      const coords = toCanvasCoords(e);
      if (coords) startDraw(coords.x, coords.y);
      return;
    }
    isDragging.current = true;
    dragStart.current = { x: e.clientX, y: e.clientY, panX, panY };
  }, [activeTool, panX, panY, toCanvasCoords, startDraw]);

  const handleMouseMove = useCallback((e: React.MouseEvent) => {
    if (activeTool === 'draw') {
      const coords = toCanvasCoords(e);
      if (coords) drawTo(coords.x, coords.y);
      return;
    }
    if (!isDragging.current) return;
    latestDelta.current = {
      dx: e.clientX - dragStart.current.x,
      dy: e.clientY - dragStart.current.y,
    };
    if (rafRef.current !== null) return;
    rafRef.current = requestAnimationFrame(() => {
      rafRef.current = null;
      setPan(
        dragStart.current.panX + latestDelta.current.dx,
        dragStart.current.panY + latestDelta.current.dy,
      );
    });
  }, [activeTool, setPan, toCanvasCoords, drawTo]);

  const handleMouseUp = useCallback(() => {
    if (activeTool === 'draw') {
      commitDraw();
      return;
    }
    isDragging.current = false;
  }, [activeTool, commitDraw]);

  const canvasDisplayWidth  = currentW * zoom;
  const canvasDisplayHeight = currentH * zoom;

  return (
    <div
      className="ultra-canvas-area"
      ref={containerRef}
      onMouseDown={handleMouseDown}
      onMouseMove={handleMouseMove}
      onMouseUp={handleMouseUp}
      onMouseLeave={handleMouseUp}
    >
      {/* Canvas viewport */}
      <div
        className="ultra-canvas-viewport"
        style={{
          transform: `translate(${panX}px, ${panY}px)`,
          width: canvasDisplayWidth,
          height: canvasDisplayHeight,
          position: 'relative',
          // Simple background in crop mode - overlay handles visual indication
          background: activeTool === 'crop' ? '#f8f9fa' : undefined,
        }}
      >
        <canvas
          ref={canvasRef}
          className="ultra-main-canvas"
          style={{
            width: canvasDisplayWidth,
            height: canvasDisplayHeight,
            display: 'block',
            cursor: activeTool === 'draw' ? 'crosshair' : undefined,
          }}
        />

        {/* Grid overlay */}
        {gridOverlay !== 'none' && (
          <GridOverlayRenderer
            type={gridOverlay}
            width={canvasDisplayWidth}
            height={canvasDisplayHeight}
          />
        )}

        {/* Crop overlay (only in crop mode) */}
        {activeTool === 'crop' && (
          <CropOverlay
            canvasWidth={canvasDisplayWidth}
            canvasHeight={canvasDisplayHeight}
            minWidth={minWidth * zoom}
          />
        )}

        {/* Layer drag/resize overlay (text, watermark, sticker, merge) */}
        {(activeTool === 'text' || activeTool === 'overlay') && (
          <TextLayerOverlay
            canvasDisplayWidth={canvasDisplayWidth}
            canvasDisplayHeight={canvasDisplayHeight}
            zoom={zoom}
          />
        )}
      </div>

      {/* Zoom indicator */}
      <div className="ultra-zoom-indicator">
        {Math.round(zoom * 100)}%
      </div>

      {/* Zoom controls */}
      <div className="ultra-zoom-controls">
        <button
          className="ultra-zoom-btn"
          onClick={() => setZoom(Math.min(zoom * 1.2, 10))}
          aria-label="Zoom in"
        >
          +
        </button>
        <button
          className="ultra-zoom-btn"
          onClick={() => setZoom(Math.max(zoom / 1.2, 0.1))}
          aria-label="Zoom out"
        >
          −
        </button>
        <button
          className="ultra-zoom-btn"
          onClick={() => {
            if (!containerRef.current || !currentW || !currentH) return;
            const { clientWidth, clientHeight } = containerRef.current;
            const fitZoom = Math.min((clientWidth - 80) / currentW, (clientHeight - 80) / currentH, 1);
            setZoom(fitZoom);
            setPan(0, 0);
          }}
          aria-label="Fit to screen"
        >
          ⊡
        </button>
      </div>

      {/* Dimensions tooltip — shows current canvas size, not original */}
      {currentW > 0 && (
        <div className="ultra-canvas-dimensions">
          {currentW} × {currentH}px
        </div>
      )}
    </div>
  );
};
