import { useState, useRef, useEffect, useCallback } from 'react';
import { useQuery } from '@tanstack/react-query';
import { developerApi } from '../../services/api';
import { ZoomIn, ZoomOut, Maximize2, Move } from 'lucide-react';
import Button from '../../components/ui/Button';

interface TableMeta {
  name: string;
  model: string;
  primaryKey: string;
  readonlyFields: string[];
  requiredFields: string[];
  relations: { field: string; targetTable: string; type: 'one' | 'many' }[];
  foreignKeys: { field: string; targetTable: string }[];
}

interface TablePosition {
  x: number;
  y: number;
}

interface ERDiagramProps {
  onSelectTable?: (tableName: string) => void;
}

export default function ERDiagram({ onSelectTable }: ERDiagramProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [zoom, setZoom] = useState(1);
  const [pan, setPan] = useState({ x: 0, y: 0 });
  const [isDragging, setIsDragging] = useState(false);
  const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
  const [tablePositions, setTablePositions] = useState<Record<string, TablePosition>>({});
  const [draggingTable, setDraggingTable] = useState<string | null>(null);

  const { data: schemaData, isLoading } = useQuery({
    queryKey: ['developer-schema'],
    queryFn: developerApi.getSchema,
  });

  const tables: TableMeta[] = schemaData?.data || [];

  // Calculate initial positions in a grid layout
  useEffect(() => {
    if (tables.length > 0 && Object.keys(tablePositions).length === 0) {
      const cols = Math.ceil(Math.sqrt(tables.length));
      const spacing = { x: 280, y: 200 };
      const newPositions: Record<string, TablePosition> = {};

      tables.forEach((table, index) => {
        const col = index % cols;
        const row = Math.floor(index / cols);
        newPositions[table.name] = {
          x: 50 + col * spacing.x,
          y: 50 + row * spacing.y,
        };
      });

      setTablePositions(newPositions);
    }
  }, [tables, tablePositions]);

  // Pan handling
  const handleMouseDown = useCallback((e: React.MouseEvent) => {
    if (e.target === e.currentTarget || (e.target as HTMLElement).tagName === 'svg') {
      setIsDragging(true);
      setDragStart({ x: e.clientX - pan.x, y: e.clientY - pan.y });
    }
  }, [pan]);

  const handleMouseMove = useCallback((e: React.MouseEvent) => {
    if (isDragging && !draggingTable) {
      setPan({
        x: e.clientX - dragStart.x,
        y: e.clientY - dragStart.y,
      });
    } else if (draggingTable) {
      const rect = containerRef.current?.getBoundingClientRect();
      if (rect) {
        setTablePositions(prev => ({
          ...prev,
          [draggingTable]: {
            x: (e.clientX - rect.left - pan.x) / zoom - 100,
            y: (e.clientY - rect.top - pan.y) / zoom - 20,
          },
        }));
      }
    }
  }, [isDragging, draggingTable, dragStart, pan, zoom]);

  const handleMouseUp = useCallback(() => {
    setIsDragging(false);
    setDraggingTable(null);
  }, []);

  const handleZoom = (delta: number) => {
    setZoom(prev => Math.min(2, Math.max(0.3, prev + delta)));
  };

  const handleReset = () => {
    setZoom(1);
    setPan({ x: 0, y: 0 });
  };

  // Calculate connection points between tables
  const getConnections = useCallback(() => {
    const connections: Array<{
      from: { table: string; x: number; y: number };
      to: { table: string; x: number; y: number };
      type: 'one' | 'many';
      label: string;
    }> = [];

    tables.forEach(table => {
      const fromPos = tablePositions[table.name];
      if (!fromPos) return;

      table.foreignKeys.forEach(fk => {
        const toPos = tablePositions[fk.targetTable];
        if (!toPos) return;

        // Find the relation type from the target table
        const targetTable = tables.find(t => t.name === fk.targetTable);
        const relation = targetTable?.relations.find(r => r.targetTable === table.name);

        connections.push({
          from: { table: table.name, x: fromPos.x + 100, y: fromPos.y + 60 },
          to: { table: fk.targetTable, x: toPos.x + 100, y: toPos.y + 60 },
          type: relation?.type || 'one',
          label: fk.field,
        });
      });
    });

    return connections;
  }, [tables, tablePositions]);

  if (isLoading) {
    return <div className="flex items-center justify-center h-full">Laden...</div>;
  }

  const connections = getConnections();

  return (
    <div className="relative h-full w-full bg-gray-50 overflow-hidden" ref={containerRef}>
      {/* Toolbar */}
      <div className="absolute top-4 right-4 z-10 flex gap-2 bg-white rounded-lg shadow-md p-2">
        <Button variant="ghost" size="sm" onClick={() => handleZoom(0.1)} title="Vergrößern">
          <ZoomIn className="w-4 h-4" />
        </Button>
        <Button variant="ghost" size="sm" onClick={() => handleZoom(-0.1)} title="Verkleinern">
          <ZoomOut className="w-4 h-4" />
        </Button>
        <Button variant="ghost" size="sm" onClick={handleReset} title="Zurücksetzen">
          <Maximize2 className="w-4 h-4" />
        </Button>
        <div className="text-xs text-gray-500 flex items-center px-2">
          {Math.round(zoom * 100)}%
        </div>
      </div>

      {/* Instructions */}
      <div className="absolute top-4 left-4 z-10 bg-white rounded-lg shadow-md p-2 text-xs text-gray-500">
        <Move className="w-3 h-3 inline mr-1" />
        Tabellen ziehen zum Verschieben
      </div>

      {/* SVG Canvas */}
      <svg
        className="w-full h-full cursor-grab"
        style={{ cursor: isDragging ? 'grabbing' : 'grab' }}
        onMouseDown={handleMouseDown}
        onMouseMove={handleMouseMove}
        onMouseUp={handleMouseUp}
        onMouseLeave={handleMouseUp}
      >
        <g transform={`translate(${pan.x}, ${pan.y}) scale(${zoom})`}>
          {/* Connection lines */}
          <defs>
            <marker
              id="arrowhead"
              markerWidth="10"
              markerHeight="7"
              refX="9"
              refY="3.5"
              orient="auto"
            >
              <polygon points="0 0, 10 3.5, 0 7" fill="#6b7280" />
            </marker>
            <marker
              id="many-marker"
              markerWidth="12"
              markerHeight="12"
              refX="6"
              refY="6"
              orient="auto"
            >
              <circle cx="6" cy="6" r="3" fill="#6b7280" />
            </marker>
          </defs>

          {connections.map((conn, idx) => {
            const dx = conn.to.x - conn.from.x;
            const dy = conn.to.y - conn.from.y;
            const midX = conn.from.x + dx / 2;
            const midY = conn.from.y + dy / 2;

            // Calculate control points for curved line
            const ctrl1X = conn.from.x + dx * 0.25;
            const ctrl1Y = conn.from.y;
            const ctrl2X = conn.from.x + dx * 0.75;
            const ctrl2Y = conn.to.y;

            return (
              <g key={idx}>
                <path
                  d={`M ${conn.from.x} ${conn.from.y} C ${ctrl1X} ${ctrl1Y}, ${ctrl2X} ${ctrl2Y}, ${conn.to.x} ${conn.to.y}`}
                  fill="none"
                  stroke="#9ca3af"
                  strokeWidth="2"
                  markerEnd="url(#arrowhead)"
                />
                {/* Relation type indicator */}
                <text
                  x={midX}
                  y={midY - 8}
                  fontSize="10"
                  fill="#6b7280"
                  textAnchor="middle"
                  className="select-none"
                >
                  {conn.type === 'many' ? '1:n' : '1:1'}
                </text>
              </g>
            );
          })}

          {/* Table boxes */}
          {tables.map(table => {
            const pos = tablePositions[table.name];
            if (!pos) return null;

            const boxWidth = 200;
            const headerHeight = 32;
            const fieldHeight = 20;
            const fields = [...new Set([table.primaryKey, ...table.foreignKeys.map(fk => fk.field)])];
            const boxHeight = headerHeight + Math.min(fields.length, 5) * fieldHeight + 8;

            return (
              <g
                key={table.name}
                transform={`translate(${pos.x}, ${pos.y})`}
                style={{ cursor: 'move' }}
                onMouseDown={(e) => {
                  e.stopPropagation();
                  setDraggingTable(table.name);
                }}
              >
                {/* Shadow */}
                <rect
                  x="3"
                  y="3"
                  width={boxWidth}
                  height={boxHeight}
                  rx="6"
                  fill="rgba(0,0,0,0.1)"
                />
                {/* Box background */}
                <rect
                  x="0"
                  y="0"
                  width={boxWidth}
                  height={boxHeight}
                  rx="6"
                  fill="white"
                  stroke="#e5e7eb"
                  strokeWidth="1"
                />
                {/* Header */}
                <rect
                  x="0"
                  y="0"
                  width={boxWidth}
                  height={headerHeight}
                  rx="6"
                  fill="#3b82f6"
                  className="cursor-pointer"
                  onClick={() => onSelectTable?.(table.name)}
                />
                <rect
                  x="0"
                  y={headerHeight - 6}
                  width={boxWidth}
                  height="6"
                  fill="#3b82f6"
                />
                <text
                  x={boxWidth / 2}
                  y="21"
                  fontSize="13"
                  fontWeight="bold"
                  fill="white"
                  textAnchor="middle"
                  className="select-none pointer-events-none"
                >
                  {table.name}
                </text>

                {/* Fields */}
                {fields.slice(0, 5).map((field, fieldIdx) => {
                  const isPK = field === table.primaryKey || table.primaryKey.includes(field);
                  const isFK = table.foreignKeys.some(fk => fk.field === field);

                  return (
                    <g key={field} transform={`translate(8, ${headerHeight + 4 + fieldIdx * fieldHeight})`}>
                      <text
                        x="0"
                        y="14"
                        fontSize="11"
                        fill={isPK ? '#dc2626' : isFK ? '#2563eb' : '#374151'}
                        fontFamily="monospace"
                        className="select-none"
                      >
                        {isPK && '🔑 '}
                        {isFK && !isPK && '🔗 '}
                        {field}
                      </text>
                    </g>
                  );
                })}
                {fields.length > 5 && (
                  <text
                    x={boxWidth / 2}
                    y={boxHeight - 4}
                    fontSize="10"
                    fill="#9ca3af"
                    textAnchor="middle"
                    className="select-none"
                  >
                    +{fields.length - 5} mehr...
                  </text>
                )}
              </g>
            );
          })}
        </g>
      </svg>

      {/* Legend */}
      <div className="absolute bottom-4 left-4 bg-white rounded-lg shadow-md p-3 text-xs">
        <div className="font-medium mb-2">Legende</div>
        <div className="space-y-1">
          <div className="flex items-center gap-2">
            <span className="text-red-600">🔑</span>
            <span>Primary Key</span>
          </div>
          <div className="flex items-center gap-2">
            <span className="text-blue-600">🔗</span>
            <span>Foreign Key</span>
          </div>
          <div className="flex items-center gap-2">
            <div className="w-6 h-0.5 bg-gray-400"></div>
            <span>Beziehung</span>
          </div>
        </div>
      </div>
    </div>
  );
}
