'use client';

import { useEffect, useRef, useState } from 'react';
import { useCanvasStore, useLayerStore, useToolStore } from '@/store';
import { useHistoryStore } from '@/store/history-store';
import { getContext, drawGrid, drawCheckerboard } from '@/lib/canvas-utils';
import { DrawCommand } from '@/core/commands';
import {
  PencilTool,
  BrushTool,
  EraserTool,
  FillTool,
  type BaseTool,
} from '@/tools';
import type { PointerState } from '@/types';
import { cn } from '@/lib/utils';

// Tool instances
const tools: Record<string, BaseTool> = {
  pencil: new PencilTool(),
  brush: new BrushTool(),
  eraser: new EraserTool(),
  fill: new FillTool(),
};

export function CanvasWithTools() {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const drawCommandRef = useRef<DrawCommand | null>(null);

  const {
    width,
    height,
    zoom,
    offsetX,
    offsetY,
    showGrid,
    gridSize,
    backgroundColor,
    selection,
    screenToCanvas,
  } = useCanvasStore();

  const { layers, getActiveLayer } = useLayerStore();
  const { activeTool, settings } = useToolStore();
  const { executeCommand } = useHistoryStore();

  const [isPanning, setIsPanning] = useState(false);
  const [panStart, setPanStart] = useState({ x: 0, y: 0 });
  const [pointer, setPointer] = useState<PointerState>({
    isDown: false,
    x: 0,
    y: 0,
    prevX: 0,
    prevY: 0,
    pressure: 1,
  });

  // Render canvas
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    const ctx = getContext(canvas);
    const container = containerRef.current;
    if (!container) return;

    // Set canvas size to match container
    const rect = container.getBoundingClientRect();
    canvas.width = rect.width;
    canvas.height = rect.height;

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

    // Save context state
    ctx.save();

    // Apply transformations
    ctx.translate(offsetX + canvas.width / 2, offsetY + canvas.height / 2);
    ctx.scale(zoom, zoom);
    ctx.translate(-width / 2, -height / 2);

    // Draw checkerboard background
    drawCheckerboard(ctx, 10, '#ffffff', '#e0e0e0');

    // Draw background color if not transparent
    if (backgroundColor && backgroundColor !== 'transparent') {
      ctx.fillStyle = backgroundColor;
      ctx.fillRect(0, 0, width, height);
    }

    // Draw all visible layers
    layers
      .filter((layer) => layer.visible && layer.canvas)
      .sort((a, b) => a.order - b.order)
      .forEach((layer) => {
        if (!layer.canvas) return;

        ctx.globalAlpha = layer.opacity;
        ctx.globalCompositeOperation = layer.blendMode as GlobalCompositeOperation;
        ctx.drawImage(layer.canvas, layer.x, layer.y);
      });

    // Reset composite operation
    ctx.globalAlpha = 1;
    ctx.globalCompositeOperation = 'source-over';

    // Draw grid if enabled
    if (showGrid) {
      drawGrid(ctx, gridSize, 'rgba(0, 0, 0, 0.15)');
    }

    // Draw selection if active
    if (selection.active) {
      ctx.strokeStyle = '#0066ff';
      ctx.lineWidth = 1 / zoom;
      ctx.setLineDash([4 / zoom, 4 / zoom]);
      ctx.strokeRect(selection.x, selection.y, selection.width, selection.height);
      ctx.setLineDash([]);
    }

    // Restore context state
    ctx.restore();
  }, [layers, width, height, zoom, offsetX, offsetY, showGrid, gridSize, backgroundColor, selection, pointer]);

  // Handle mouse wheel for zooming
  const handleWheel = (e: React.WheelEvent) => {
    if (e.ctrlKey || e.metaKey) {
      e.preventDefault();
      const { zoomIn, zoomOut } = useCanvasStore.getState();
      if (e.deltaY < 0) {
        zoomIn();
      } else {
        zoomOut();
      }
    }
  };

  // Handle pointer down
  const handlePointerDown = (e: React.PointerEvent) => {
    const rect = canvasRef.current?.getBoundingClientRect();
    if (!rect) return;

    const screenX = e.clientX - rect.left;
    const screenY = e.clientY - rect.top;
    const canvasPos = screenToCanvas(screenX, screenY);

    // Check for panning
    if (e.button === 1 || (e.button === 0 && e.shiftKey)) {
      setIsPanning(true);
      setPanStart({ x: e.clientX - offsetX, y: e.clientY - offsetY });
      e.preventDefault();
      return;
    }

    // Drawing tools
    if (e.button === 0 && !e.shiftKey && ['pencil', 'brush', 'eraser', 'fill'].includes(activeTool)) {
      const activeLayer = getActiveLayer();
      if (!activeLayer || !activeLayer.canvas || activeLayer.locked) return;

      const newPointer: PointerState = {
        isDown: true,
        x: canvasPos.x,
        y: canvasPos.y,
        prevX: canvasPos.x,
        prevY: canvasPos.y,
        pressure: e.pressure || 1,
      };

      setPointer(newPointer);

      // Create draw command for history
      drawCommandRef.current = new DrawCommand(activeLayer.id, tools[activeTool].name);

      // Call tool's onPointerDown
      const ctx = activeLayer.canvas.getContext('2d');
      if (ctx) {
        tools[activeTool].onPointerDown(newPointer, ctx, settings);
      }
    }
  };

  // Handle pointer move
  const handlePointerMove = (e: React.PointerEvent) => {
    const rect = canvasRef.current?.getBoundingClientRect();
    if (!rect) return;

    const screenX = e.clientX - rect.left;
    const screenY = e.clientY - rect.top;
    const canvasPos = screenToCanvas(screenX, screenY);

    // Panning
    if (isPanning) {
      const { setPanOffset } = useCanvasStore.getState();
      setPanOffset(e.clientX - panStart.x, e.clientY - panStart.y);
      return;
    }

    // Drawing
    if (pointer.isDown && ['pencil', 'brush', 'eraser'].includes(activeTool)) {
      const activeLayer = getActiveLayer();
      if (!activeLayer || !activeLayer.canvas) return;

      const newPointer: PointerState = {
        ...pointer,
        x: canvasPos.x,
        y: canvasPos.y,
        pressure: e.pressure || 1,
      };

      setPointer(newPointer);

      const ctx = activeLayer.canvas.getContext('2d');
      if (ctx) {
        tools[activeTool].onPointerMove(newPointer, ctx, settings);
      }
    }
  };

  // Handle pointer up
  const handlePointerUp = (e: React.PointerEvent) => {
    if (isPanning) {
      setIsPanning(false);
      return;
    }

    if (pointer.isDown && ['pencil', 'brush', 'eraser', 'fill'].includes(activeTool)) {
      const activeLayer = getActiveLayer();
      if (!activeLayer || !activeLayer.canvas) return;

      const ctx = activeLayer.canvas.getContext('2d');
      if (ctx) {
        tools[activeTool].onPointerUp(pointer, ctx, settings);
      }

      // Capture after state and add to history
      if (drawCommandRef.current) {
        drawCommandRef.current.captureAfterState();
        executeCommand(drawCommandRef.current);
        drawCommandRef.current = null;
      }

      setPointer({ ...pointer, isDown: false });
    }
  };

  return (
    <div
      ref={containerRef}
      className={cn(
        'relative h-full w-full overflow-hidden bg-canvas-bg',
        isPanning ? 'cursor-grabbing' : `cursor-${tools[activeTool]?.getCursor(settings) || 'default'}`
      )}
      onWheel={handleWheel}
      onPointerDown={handlePointerDown}
      onPointerMove={handlePointerMove}
      onPointerUp={handlePointerUp}
      onPointerLeave={handlePointerUp}
    >
      <canvas
        ref={canvasRef}
        className="absolute inset-0"
      />
    </div>
  );
}
