import React, { useRef, useState, useCallback, useMemo, useEffect } from 'react';
import type { BattleSession, BattleMap } from '@/shared/types';
import { Token } from './token';
import { cn } from '@/shared/lib/utils';

interface BattleCanvasProps {
  session: BattleSession;
  map: BattleMap | null;
  isGM: boolean;
  selectedTokenId: string | null;
  onSelectToken: (tokenId: string | null) => void;
  onMoveToken: (tokenId: string, positionX: number, positionY: number) => void;
}

const API_URL = import.meta.env.VITE_API_URL?.replace('/api', '') || 'http://localhost:5000';

export function BattleCanvas({
  session,
  map,
  isGM,
  selectedTokenId,
  onSelectToken,
  onMoveToken,
}: BattleCanvasProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
  const [draggedToken, setDraggedToken] = useState<string | null>(null);
  const [showGrid, setShowGrid] = useState(true);

  // Calculate cell size based on container and grid dimensions
  const cellSize = useMemo(() => {
    if (!map || containerSize.width === 0 || containerSize.height === 0) return 40;

    const cellWidth = containerSize.width / map.gridSizeX;
    const cellHeight = containerSize.height / map.gridSizeY;

    // Use the smaller dimension to ensure grid fits
    return Math.floor(Math.min(cellWidth, cellHeight));
  }, [map, containerSize]);

  // Calculate canvas dimensions
  const canvasSize = useMemo(() => {
    if (!map) return { width: 800, height: 600 };
    return {
      width: cellSize * map.gridSizeX,
      height: cellSize * map.gridSizeY,
    };
  }, [map, cellSize]);

  // Update container size on resize
  useEffect(() => {
    const updateSize = () => {
      if (containerRef.current) {
        setContainerSize({
          width: containerRef.current.clientWidth,
          height: containerRef.current.clientHeight,
        });
      }
    };

    updateSize();
    window.addEventListener('resize', updateSize);
    return () => window.removeEventListener('resize', updateSize);
  }, []);

  // Handle drag start
  const handleDragStart = useCallback((tokenId: string) => (e: React.DragEvent | React.TouchEvent) => {
    if (!isGM) return;

    setDraggedToken(tokenId);
    onSelectToken(tokenId);

    if ('dataTransfer' in e) {
      e.dataTransfer.effectAllowed = 'move';
      e.dataTransfer.setData('text/plain', tokenId);
    }
  }, [isGM, onSelectToken]);

  // Handle drop on canvas
  const handleDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    if (!draggedToken || !isGM || !map) return;

    const rect = e.currentTarget.getBoundingClientRect();
    const x = e.clientX - rect.left - map.gridOffsetX;
    const y = e.clientY - rect.top - map.gridOffsetY;

    // Calculate grid position
    const gridX = Math.floor(x / cellSize);
    const gridY = Math.floor(y / cellSize);

    // Clamp to grid bounds
    const clampedX = Math.max(0, Math.min(gridX, map.gridSizeX - 1));
    const clampedY = Math.max(0, Math.min(gridY, map.gridSizeY - 1));

    onMoveToken(draggedToken, clampedX, clampedY);
    setDraggedToken(null);
  }, [draggedToken, isGM, map, cellSize, onMoveToken]);

  // Handle drag over
  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
  }, []);

  // Handle canvas click (deselect token)
  const handleCanvasClick = useCallback((e: React.MouseEvent) => {
    if (e.target === e.currentTarget) {
      onSelectToken(null);
    }
  }, [onSelectToken]);

  // Render grid lines
  const gridLines = useMemo(() => {
    if (!map || !showGrid) return null;

    const lines: React.ReactElement[] = [];

    // Vertical lines
    for (let x = 0; x <= map.gridSizeX; x++) {
      lines.push(
        <line
          key={`v-${x}`}
          x1={x * cellSize + map.gridOffsetX}
          y1={map.gridOffsetY}
          x2={x * cellSize + map.gridOffsetX}
          y2={canvasSize.height + map.gridOffsetY}
          stroke="rgba(255, 255, 255, 0.3)"
          strokeWidth={1}
        />
      );
    }

    // Horizontal lines
    for (let y = 0; y <= map.gridSizeY; y++) {
      lines.push(
        <line
          key={`h-${y}`}
          x1={map.gridOffsetX}
          y1={y * cellSize + map.gridOffsetY}
          x2={canvasSize.width + map.gridOffsetX}
          y2={y * cellSize + map.gridOffsetY}
          stroke="rgba(255, 255, 255, 0.3)"
          strokeWidth={1}
        />
      );
    }

    return lines;
  }, [map, showGrid, cellSize, canvasSize]);

  return (
    <div className="flex-1 flex flex-col bg-black/50 rounded-lg overflow-hidden">
      {/* Toolbar */}
      <div className="flex items-center gap-2 p-2 bg-black/30 border-b border-white/10">
        <button
          onClick={() => setShowGrid(!showGrid)}
          className={cn(
            'px-3 py-1 text-sm rounded transition-colors',
            showGrid ? 'bg-primary text-white' : 'bg-white/10 text-white/70 hover:bg-white/20',
          )}
        >
          Grid
        </button>
        {map && (
          <span className="text-sm text-white/50">
            {map.gridSizeX} x {map.gridSizeY} ({cellSize}px)
          </span>
        )}
      </div>

      {/* Canvas container */}
      <div
        ref={containerRef}
        className="flex-1 overflow-auto flex items-center justify-center p-4"
      >
        <div
          className="relative bg-gray-900 shadow-2xl"
          style={{
            width: canvasSize.width + (map?.gridOffsetX ?? 0),
            height: canvasSize.height + (map?.gridOffsetY ?? 0),
          }}
          onClick={handleCanvasClick}
          onDrop={handleDrop}
          onDragOver={handleDragOver}
        >
          {/* Map background */}
          {map && (
            <img
              src={`${API_URL}${map.imageUrl}`}
              alt={map.name}
              className="absolute inset-0 w-full h-full object-cover pointer-events-none"
              draggable={false}
            />
          )}

          {/* Grid overlay */}
          <svg
            className="absolute inset-0 w-full h-full pointer-events-none"
            style={{ zIndex: 5 }}
          >
            {gridLines}
          </svg>

          {/* Tokens */}
          <div
            className="absolute"
            style={{
              left: map?.gridOffsetX ?? 0,
              top: map?.gridOffsetY ?? 0,
              width: canvasSize.width,
              height: canvasSize.height,
            }}
          >
            {session.tokens.map((token) => (
              <Token
                key={token.id}
                token={token}
                cellSize={cellSize}
                isSelected={token.id === selectedTokenId}
                isGM={isGM}
                onSelect={() => onSelectToken(token.id)}
                onDragStart={handleDragStart(token.id)}
              />
            ))}
          </div>

          {/* No map placeholder */}
          {!map && (
            <div className="absolute inset-0 flex items-center justify-center text-white/50">
              <p>Keine Karte ausgewählt</p>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
