import { ref, type Ref } from 'vue';
import { useSettingsStore } from '@/stores/useSettingsStore';
import type { Sprite } from '@/types/sprites';

export interface Canvas2DOptions {
  pixelPerfect?: Ref<boolean> | boolean;
}

export function useCanvas2D(canvasRef: Ref<HTMLCanvasElement | null>, options?: Canvas2DOptions) {
  const ctx = ref<CanvasRenderingContext2D | null>(null);
  const settingsStore = useSettingsStore();

  const initContext = () => {
    if (canvasRef.value) {
      ctx.value = canvasRef.value.getContext('2d');
      applySmoothing();
    }
    return ctx.value;
  };

  const applySmoothing = () => {
    if (ctx.value) {
      const pixelPerfect = options?.pixelPerfect;
      const isPixelPerfect = typeof pixelPerfect === 'boolean' ? pixelPerfect : (pixelPerfect?.value ?? settingsStore.pixelPerfect);
      ctx.value.imageSmoothingEnabled = !isPixelPerfect;
    }
  };

  const clear = () => {
    if (!canvasRef.value || !ctx.value) return;
    ctx.value.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height);
  };

  const setCanvasSize = (width: number, height: number) => {
    if (canvasRef.value) {
      canvasRef.value.width = width;
      canvasRef.value.height = height;
    }
  };

  const fillRect = (x: number, y: number, width: number, height: number, color: string) => {
    if (!ctx.value) return;
    ctx.value.fillStyle = color;
    ctx.value.fillRect(Math.floor(x), Math.floor(y), width, height);
  };

  const strokeRect = (x: number, y: number, width: number, height: number, color: string, lineWidth = 1) => {
    if (!ctx.value) return;
    ctx.value.strokeStyle = color;
    ctx.value.lineWidth = lineWidth;
    ctx.value.strokeRect(Math.floor(x), Math.floor(y), width, height);
  };

  const drawImage = (img: HTMLImageElement | HTMLCanvasElement, x: number, y: number, alpha = 1) => {
    if (!ctx.value) return;
    const prevAlpha = ctx.value.globalAlpha;
    ctx.value.globalAlpha = alpha;
    ctx.value.drawImage(img, Math.floor(x), Math.floor(y));
    ctx.value.globalAlpha = prevAlpha;
  };

  const setGlobalAlpha = (alpha: number) => {
    if (ctx.value) {
      ctx.value.globalAlpha = alpha;
    }
  };

  const resetGlobalAlpha = () => {
    if (ctx.value) {
      ctx.value.globalAlpha = 1.0;
    }
  };

  // Helper to ensure integer positions for pixel-perfect rendering
  const ensureIntegerPositions = <T extends { x: number; y: number }>(items: T[]) => {
    items.forEach(item => {
      item.x = Math.floor(item.x);
      item.y = Math.floor(item.y);
    });
  };

  // Centralized force redraw handler
  const createForceRedrawHandler = <T extends { x: number; y: number }>(items: T[], drawCallback: () => void) => {
    return () => {
      ensureIntegerPositions(items);
      applySmoothing();
      drawCallback();
    };
  };

  // Get mouse position relative to canvas, accounting for zoom
  const getMousePosition = (event: MouseEvent, zoom = 1): { x: number; y: number } | null => {
    if (!canvasRef.value) return null;

    const rect = canvasRef.value.getBoundingClientRect();
    const scaleX = canvasRef.value.width / (rect.width / zoom);
    const scaleY = canvasRef.value.height / (rect.height / zoom);

    return {
      x: ((event.clientX - rect.left) / zoom) * scaleX,
      y: ((event.clientY - rect.top) / zoom) * scaleY,
    };
  };

  // Helper to attach load/error listeners to images that aren't yet loaded
  const attachImageListeners = (sprites: Sprite[], onLoad: () => void, tracked: WeakSet<HTMLImageElement>) => {
    sprites.forEach(sprite => {
      const img = sprite.img as HTMLImageElement | undefined;
      if (img && !tracked.has(img)) {
        tracked.add(img);
        if (!img.complete) {
          img.addEventListener('load', onLoad, { once: true });
          img.addEventListener('error', onLoad, { once: true });
        }
      }
    });
  };

  // Fill cell background with selected color or transparent
  const fillCellBackground = (x: number, y: number, width: number, height: number) => {
    if (settingsStore.backgroundColor === 'transparent') return;
    const color = settingsStore.backgroundColor === 'custom' ? settingsStore.backgroundColor : settingsStore.backgroundColor;
    fillRect(x, y, width, height, color);
  };

  // Stroke grid with theme-aware color
  const strokeGridCell = (x: number, y: number, width: number, height: number) => {
    const color = settingsStore.darkMode ? '#4B5563' : '#e5e7eb';
    strokeRect(x, y, width, height, color, 1);
  };

  return {
    ctx,
    canvasRef,
    initContext,
    applySmoothing,
    clear,
    setCanvasSize,
    fillRect,
    strokeRect,
    drawImage,
    setGlobalAlpha,
    resetGlobalAlpha,
    ensureIntegerPositions,
    createForceRedrawHandler,
    getMousePosition,
    attachImageListeners,
    fillCellBackground,
    strokeGridCell,
  };
}
