/**
 * MemoryGraph - 记忆图谱可视化组件
 *
 * 使用 Canvas 实现力导向图布局，展示记忆之间的关联关系。
 *
 * 功能:
 * - 力导向布局算法
 * - 节点拖拽
 * - 类型筛选
 * - 搜索高亮
 * - 导出图片
 */

import { useCallback, useEffect, useRef, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
  ZoomIn,
  ZoomOut,
  Maximize2,
  Download,
  Search,
  Filter,
  X,
  RefreshCw,
  Tag,
  Clock,
  Star,
} from 'lucide-react';
import { Button, Badge } from './ui';
import {
  useMemoryGraphStore,
  type GraphNode,
  type GraphEdge,
  type MemoryType,
} from '../store/memoryGraphStore';
import { useConversationStore } from '../store/chat/conversationStore';
import { cardHover, defaultTransition } from '../lib/animations';

// Mark as intentionally unused for future use
void cardHover;
void defaultTransition;

// === Constants ===

const NODE_COLORS: Record<MemoryType, { fill: string; stroke: string; text: string }> = {
  fact: { fill: '#3b82f6', stroke: '#1d4ed8', text: '#ffffff' },
  preference: { fill: '#f59e0b', stroke: '#d97706', text: '#ffffff' },
  lesson: { fill: '#10b981', stroke: '#059669', text: '#ffffff' },
  context: { fill: '#8b5cf6', stroke: '#7c3aed', text: '#ffffff' },
  task: { fill: '#ef4444', stroke: '#dc2626', text: '#ffffff' },
};

const TYPE_LABELS: Record<MemoryType, string> = {
  fact: '事实',
  preference: '偏好',
  lesson: '经验',
  context: '上下文',
  task: '任务',
};

const NODE_RADIUS = 20;
const REPULSION_STRENGTH = 5000;
const ATTRACTION_STRENGTH = 0.01;
const DAMPING = 0.9;
const MIN_VELOCITY = 0.01;

// === Force-Directed Layout ===

function simulateStep(
  nodes: GraphNode[],
  edges: GraphEdge[],
  width: number,
  height: number
): GraphNode[] {
  const updatedNodes = nodes.map(node => ({ ...node }));

  // 斥力 (节点间)
  for (let i = 0; i < updatedNodes.length; i++) {
    for (let j = i + 1; j < updatedNodes.length; j++) {
      const n1 = updatedNodes[i];
      const n2 = updatedNodes[j];
      const dx = n2.x - n1.x;
      const dy = n2.y - n1.y;
      const dist = Math.sqrt(dx * dx + dy * dy) || 1;
      const force = REPULSION_STRENGTH / (dist * dist);

      const fx = (dx / dist) * force;
      const fy = (dy / dist) * force;

      n1.vx -= fx;
      n1.vy -= fy;
      n2.vx += fx;
      n2.vy += fy;
    }
  }

  // 引力 (边)
  for (const edge of edges) {
    const source = updatedNodes.find(n => n.id === edge.source);
    const target = updatedNodes.find(n => n.id === edge.target);
    if (!source || !target) continue;

    const dx = target.x - source.x;
    const dy = target.y - source.y;
    const dist = Math.sqrt(dx * dx + dy * dy) || 1;
    const force = dist * ATTRACTION_STRENGTH * edge.strength;

    const fx = (dx / dist) * force;
    const fy = (dy / dist) * force;

    source.vx += fx;
    source.vy += fy;
    target.vx -= fx;
    target.vy -= fy;
  }

  // 中心引力
  const centerX = width / 2;
  const centerY = height / 2;
  const centerForce = 0.001;

  for (const node of updatedNodes) {
    node.vx += (centerX - node.x) * centerForce;
    node.vy += (centerY - node.y) * centerForce;
  }

  // 更新位置
  for (const node of updatedNodes) {
    node.vx *= DAMPING;
    node.vy *= DAMPING;

    if (Math.abs(node.vx) < MIN_VELOCITY) node.vx = 0;
    if (Math.abs(node.vy) < MIN_VELOCITY) node.vy = 0;

    node.x += node.vx;
    node.y += node.vy;

    // 边界约束
    node.x = Math.max(NODE_RADIUS, Math.min(width - NODE_RADIUS, node.x));
    node.y = Math.max(NODE_RADIUS, Math.min(height - NODE_RADIUS, node.y));
  }

  return updatedNodes;
}

// === Main Component ===

interface MemoryGraphProps {
  className?: string;
}

export function MemoryGraph({ className = '' }: MemoryGraphProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const animationRef = useRef<number | null>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [dragNode, setDragNode] = useState<string | null>(null);
  const [showFilters, setShowFilters] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');

  const currentAgent = useConversationStore((s) => s.currentAgent);
  const agentId = currentAgent?.id || 'zclaw-main';

  const {
    isLoading,
    error,
    filter,
    layout,
    selectedNodeId,
    showLabels,
    simulationRunning,
    loadGraph,
    setFilter,
    resetFilter,
    setLayout,
    selectNode,
    toggleLabels,
    startSimulation,
    stopSimulation,
    updateNodePositions,
    highlightSearch,
    getFilteredNodes,
    getFilteredEdges,
  } = useMemoryGraphStore();

  const filteredNodes = getFilteredNodes();
  const filteredEdges = getFilteredEdges();

  // 加载图谱
  useEffect(() => {
    loadGraph(agentId);
  }, [agentId, loadGraph]);

  // 力导向模拟
  useEffect(() => {
    if (!simulationRunning || filteredNodes.length === 0) return;

    const canvas = canvasRef.current;
    if (!canvas) return;

    const simulate = () => {
      const updated = simulateStep(filteredNodes, filteredEdges, layout.width, layout.height);
      updateNodePositions(updated.map(n => ({ id: n.id, x: n.x, y: n.y })));
      animationRef.current = requestAnimationFrame(simulate);
    };

    animationRef.current = requestAnimationFrame(simulate);

    return () => {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, [simulationRunning, filteredNodes.length, filteredEdges, layout.width, layout.height, updateNodePositions]);

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

    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    const dpr = window.devicePixelRatio || 1;
    canvas.width = layout.width * dpr;
    canvas.height = layout.height * dpr;
    ctx.scale(dpr, dpr);

    // 清空画布 - 使用浅色背景匹配系统主题
    ctx.fillStyle = '#f9fafb'; // gray-50
    ctx.fillRect(0, 0, layout.width, layout.height);

    // 应用变换
    ctx.save();
    ctx.translate(layout.offsetX, layout.offsetY);
    ctx.scale(layout.zoom, layout.zoom);

    // 绘制边
    for (const edge of filteredEdges) {
      const source = filteredNodes.find(n => n.id === edge.source);
      const target = filteredNodes.find(n => n.id === edge.target);
      if (!source || !target) continue;

      ctx.beginPath();
      ctx.moveTo(source.x, source.y);
      ctx.lineTo(target.x, target.y);
      ctx.strokeStyle = edge.type === 'reference'
        ? 'rgba(59, 130, 246, 0.5)'
        : edge.type === 'related'
        ? 'rgba(245, 158, 11, 0.3)'
        : 'rgba(139, 92, 246, 0.2)';
      ctx.lineWidth = edge.strength * 3;
      ctx.stroke();
    }

    // 绘制节点
    for (const node of filteredNodes) {
      const colors = NODE_COLORS[node.type];
      const isSelected = node.id === selectedNodeId;
      const radius = isSelected ? NODE_RADIUS * 1.3 : NODE_RADIUS;

      // 高亮效果
      if (node.isHighlighted) {
        ctx.beginPath();
        ctx.arc(node.x, node.y, radius + 8, 0, Math.PI * 2);
        ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
        ctx.fill();
      }

      // 节点圆形
      ctx.beginPath();
      ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
      ctx.fillStyle = colors.fill;
      ctx.fill();
      ctx.strokeStyle = colors.stroke;
      ctx.lineWidth = isSelected ? 3 : 1;
      ctx.stroke();

      // 节点标签
      if (showLabels) {
        ctx.font = '10px Inter, system-ui, sans-serif';
        ctx.fillStyle = colors.text;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        const text = node.label.slice(0, 10);
        ctx.fillText(text, node.x, node.y);
      }
    }

    ctx.restore();

    // 图例
    const legendY = 20;
    let legendX = 20;
    ctx.font = '12px Inter, system-ui, sans-serif';

    for (const [type, label] of Object.entries(TYPE_LABELS)) {
      const colors = NODE_COLORS[type as MemoryType];
      ctx.beginPath();
      ctx.arc(legendX, legendY, 6, 0, Math.PI * 2);
      ctx.fillStyle = colors.fill;
      ctx.fill();
      ctx.fillStyle = '#6b7280'; // gray-500 for better visibility on light background
      ctx.textAlign = 'left';
      ctx.fillText(label, legendX + 12, legendY + 4);
      legendX += 70;
    }

  }, [filteredNodes, filteredEdges, layout, selectedNodeId, showLabels]);

  // 鼠标事件处理
  const handleMouseDown = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    const rect = canvas.getBoundingClientRect();
    const x = (e.clientX - rect.left - layout.offsetX) / layout.zoom;
    const y = (e.clientY - rect.top - layout.offsetY) / layout.zoom;

    // 检查是否点击了节点
    for (const node of filteredNodes) {
      const dx = x - node.x;
      const dy = y - node.y;
      if (dx * dx + dy * dy < NODE_RADIUS * NODE_RADIUS) {
        setDragNode(node.id);
        setIsDragging(true);
        selectNode(node.id);
        return;
      }
    }

    selectNode(null);
  }, [filteredNodes, layout, selectNode]);

  const handleMouseMove = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    if (!isDragging || !dragNode) return;

    const canvas = canvasRef.current;
    if (!canvas) return;

    const rect = canvas.getBoundingClientRect();
    const x = (e.clientX - rect.left - layout.offsetX) / layout.zoom;
    const y = (e.clientY - rect.top - layout.offsetY) / layout.zoom;

    updateNodePositions([{ id: dragNode, x, y }]);
  }, [isDragging, dragNode, layout, updateNodePositions]);

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

  const handleWheel = useCallback((e: React.WheelEvent<HTMLCanvasElement>) => {
    e.preventDefault();
    const delta = e.deltaY > 0 ? 0.9 : 1.1;
    const newZoom = Math.max(0.2, Math.min(3, layout.zoom * delta));
    setLayout({ zoom: newZoom });
  }, [layout.zoom, setLayout]);

  const handleSearch = useCallback((query: string) => {
    setSearchQuery(query);
    highlightSearch(query);
  }, [highlightSearch]);

  const handleExport = useCallback(async () => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    const dataUrl = canvas.toDataURL('image/png');
    const a = document.createElement('a');
    a.href = dataUrl;
    a.download = `memory-graph-${new Date().toISOString().slice(0, 10)}.png`;
    a.click();
  }, []);

  const selectedNode = filteredNodes.find(n => n.id === selectedNodeId);

  return (
    <div className={`flex flex-col h-full ${className}`}>
      {/* 工具栏 */}
      <div className="flex items-center gap-2 p-2 bg-gray-100 dark:bg-gray-800/50 rounded-t-lg border-b border-gray-200 dark:border-gray-700">
        {/* 搜索框 */}
        <div className="relative flex-1 max-w-xs">
          <Search className="absolute left-2 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
          <input
            type="text"
            placeholder="搜索记忆..."
            value={searchQuery}
            onChange={(e) => handleSearch(e.target.value)}
            className="w-full pl-8 pr-2 py-1 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded text-sm text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:border-orange-400 dark:focus:border-blue-500"
          />
        </div>

        {/* 筛选按钮 */}
        <Button
          variant={showFilters ? 'primary' : 'ghost'}
          size="sm"
          onClick={() => setShowFilters(!showFilters)}
          className="flex items-center gap-1"
        >
          <Filter className="w-4 h-4" />
          筛选
        </Button>

        {/* 缩放控制 */}
        <div className="flex items-center gap-1 border-l border-gray-700 pl-2">
          <Button
            variant="ghost"
            size="sm"
            onClick={() => setLayout({ zoom: Math.max(0.2, layout.zoom * 0.8) })}
          >
            <ZoomOut className="w-4 h-4" />
          </Button>
          <span className="text-xs text-gray-400 min-w-[3rem] text-center">
            {Math.round(layout.zoom * 100)}%
          </span>
          <Button
            variant="ghost"
            size="sm"
            onClick={() => setLayout({ zoom: Math.min(3, layout.zoom * 1.2) })}
          >
            <ZoomIn className="w-4 h-4" />
          </Button>
          <Button
            variant="ghost"
            size="sm"
            onClick={() => setLayout({ zoom: 1, offsetX: 0, offsetY: 0 })}
          >
            <Maximize2 className="w-4 h-4" />
          </Button>
        </div>

        {/* 模拟控制 */}
        <div className="flex items-center gap-1 border-l border-gray-700 pl-2">
          <Button
            variant={simulationRunning ? 'primary' : 'ghost'}
            size="sm"
            onClick={() => simulationRunning ? stopSimulation() : startSimulation()}
          >
            <RefreshCw className={`w-4 h-4 ${simulationRunning ? 'animate-spin' : ''}`} />
            {simulationRunning ? '停止' : '布局'}
          </Button>
        </div>

        {/* 导出 */}
        <Button variant="ghost" size="sm" onClick={handleExport}>
          <Download className="w-4 h-4" />
        </Button>

        {/* 标签切换 */}
        <Button variant="ghost" size="sm" onClick={toggleLabels}>
          <Tag className="w-4 h-4" />
        </Button>
      </div>

      {/* 筛选面板 */}
      <AnimatePresence>
        {showFilters && (
          <motion.div
            initial={{ height: 0, opacity: 0 }}
            animate={{ height: 'auto', opacity: 1 }}
            exit={{ height: 0, opacity: 0 }}
            className="overflow-hidden bg-gray-50 dark:bg-gray-800/30 border-b border-gray-200 dark:border-gray-700"
          >
            <div className="p-3 flex flex-wrap gap-3">
              {/* 类型筛选 */}
              <div className="flex items-center gap-2">
                <span className="text-xs text-gray-400">类型:</span>
                {(Object.keys(TYPE_LABELS) as MemoryType[]).map(type => (
                  <button
                    key={type}
                    onClick={() => {
                      const types = filter.types.includes(type)
                        ? filter.types.filter(t => t !== type)
                        : [...filter.types, type];
                      setFilter({ types });
                    }}
                    className={`px-2 py-1 text-xs rounded ${
                      filter.types.includes(type)
                        ? 'bg-orange-500 text-white'
                        : 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
                    }`}
                  >
                    {TYPE_LABELS[type]}
                  </button>
                ))}
              </div>

              {/* 重要性筛选 */}
              <div className="flex items-center gap-2">
                <span className="text-xs text-gray-400">重要性:</span>
                <input
                  type="range"
                  min="0"
                  max="10"
                  value={filter.minImportance}
                  onChange={(e) => setFilter({ minImportance: parseInt(e.target.value) })}
                  className="w-20"
                />
                <span className="text-xs text-gray-300">{filter.minImportance}+</span>
              </div>

              {/* 重置 */}
              <Button variant="ghost" size="sm" onClick={resetFilter}>
                <X className="w-3 h-3 mr-1" />
                重置
              </Button>
            </div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* 图谱画布 */}
      <div className="flex-1 relative overflow-hidden bg-gray-50 dark:bg-gray-900">
        {isLoading && (
          <div className="absolute inset-0 flex items-center justify-center bg-gray-50/80 dark:bg-gray-900/80 z-10">
            <RefreshCw className="w-8 h-8 text-blue-500 animate-spin" />
          </div>
        )}

        {error && (
          <div className="absolute inset-0 flex items-center justify-center">
            <div className="text-red-400 text-sm">{error}</div>
          </div>
        )}

        <canvas
          ref={canvasRef}
          style={{ width: layout.width, height: layout.height }}
          className="cursor-grab active:cursor-grabbing"
          onMouseDown={handleMouseDown}
          onMouseMove={handleMouseMove}
          onMouseUp={handleMouseUp}
          onMouseLeave={handleMouseUp}
          onWheel={handleWheel}
        />

        {/* 节点详情面板 */}
        <AnimatePresence>
          {selectedNode && (
            <motion.div
              initial={{ opacity: 0, x: 20 }}
              animate={{ opacity: 1, x: 0 }}
              exit={{ opacity: 0, x: 20 }}
              className="absolute top-4 right-4 w-64 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-4 shadow-xl"
            >
              <div className="flex items-center justify-between mb-3">
                <Badge variant={selectedNode.type as any}>
                  {TYPE_LABELS[selectedNode.type]}
                </Badge>
                <button
                  onClick={() => selectNode(null)}
                  className="text-gray-400 hover:text-gray-600 dark:hover:text-white"
                >
                  <X className="w-4 h-4" />
                </button>
              </div>

              <p className="text-sm text-gray-200 mb-3">{selectedNode.label}</p>

              <div className="space-y-2 text-xs text-gray-500 dark:text-gray-400">
                <div className="flex items-center gap-2">
                  <Star className="w-3 h-3" />
                  重要性: {selectedNode.importance}
                </div>
                <div className="flex items-center gap-2">
                  <Clock className="w-3 h-3" />
                  访问次数: {selectedNode.accessCount}
                </div>
                <div className="flex items-center gap-2">
                  <Tag className="w-3 h-3" />
                  创建: {new Date(selectedNode.createdAt).toLocaleDateString()}
                </div>
              </div>

              {/* 关联边统计 */}
              <div className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700">
                <div className="text-xs text-gray-500 dark:text-gray-400 mb-1">关联记忆:</div>
                <div className="text-sm text-gray-700 dark:text-gray-200">
                  {filteredEdges.filter(
                    e => e.source === selectedNode.id || e.target === selectedNode.id
                  ).length} 个
                </div>
              </div>
            </motion.div>
          )}
        </AnimatePresence>

        {/* 空状态 */}
        {!isLoading && filteredNodes.length === 0 && (
          <div className="absolute inset-0 flex items-center justify-center">
            <div className="text-center text-gray-500">
              <Tag className="w-12 h-12 mx-auto mb-2 opacity-50" />
              <p>暂无记忆数据</p>
              <p className="text-sm mt-1">开始对话后将自动记录记忆</p>
            </div>
          </div>
        )}
      </div>

      {/* 状态栏 */}
      <div className="flex items-center justify-between px-3 py-1 bg-gray-100 dark:bg-gray-800/50 rounded-b-lg text-xs text-gray-500 dark:text-gray-400">
        <div className="flex items-center gap-4">
          <span>节点: {filteredNodes.length}</span>
          <span>关联: {filteredEdges.length}</span>
        </div>
        <div className="flex items-center gap-2">
          {simulationRunning && (
            <span className="flex items-center gap-1 text-green-400">
              <RefreshCw className="w-3 h-3 animate-spin" />
              布局中...
            </span>
          )}
        </div>
      </div>
    </div>
  );
}

export default MemoryGraph;
