"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Background, BackgroundVariant, Controls, PanOnScrollMode, ReactFlow, useNodesInitialized, useNodesState, useReactFlow, type Node, type OnMove, type Rect } from "@xyflow/react";
import type { CanvasItem, ExecutionViewV8, OpenTarget } from "@/lib/types";
import { buildHorizontalLayout, type CanvasNodeData } from "@/lib/layout";
import { StoryCard } from "@/components/flow/StoryCard";
import { RoundSummaryCard } from "@/components/flow/RoundSummaryCard";
import { RunResultCard } from "@/components/flow/RunResultCard";
import { RoundFrame } from "@/components/flow/RoundFrame";
import { CandidateCard } from "@/components/flow/CandidateCard";
import { AgentRegion } from "@/components/flow/AgentRegion";
import { BranchFrame } from "@/components/flow/BranchFrame";
import { RetrievalStageFrame } from "@/components/flow/RetrievalStageFrame";
import { DirectToolGroupCard } from "@/components/flow/DirectToolGroupCard";
import { RetrievalAgentCard } from "@/components/flow/RetrievalAgentCard";
import { AgentDecisionCard } from "@/components/decision/AgentDecisionCard";

const nodeTypes = { storyCard: StoryCard, agentDecision: AgentDecisionCard, candidateCard: CandidateCard, roundSummary: RoundSummaryCard, finalResult: RunResultCard, roundFrame: RoundFrame, agentRegion: AgentRegion, branchFrame: BranchFrame, retrievalStageFrame: RetrievalStageFrame, directToolGroup: DirectToolGroupCard, retrievalAgent: RetrievalAgentCard };
const MIN_CANVAS_ZOOM = .2;
const INITIAL_VIEWPORT = { x: 18, y: 94, zoom: MIN_CANVAS_ZOOM };

export function centeredOverviewViewport(bounds: Pick<Rect, "x" | "width">, canvasWidth: number) {
  return {
    x: canvasWidth / 2 - (bounds.x + bounds.width / 2) * MIN_CANVAS_ZOOM,
    y: INITIAL_VIEWPORT.y,
    zoom: MIN_CANVAS_ZOOM,
  };
}

interface Props {
  view: ExecutionViewV8;
  expandedRounds: Set<number>;
  expandedBranches: Set<string>;
  expandedRetrievalAgents: Set<string>;
  onToggleRound: (round: number) => void;
  onToggleBranch: (round: number, branchId: number) => void;
  onToggleRetrievalAgent: (agentId: string) => void;
  onOpen: (item: CanvasItem, target: OpenTarget) => void;
  onPrompt: (promptRef: string) => void;
  selectedId?: string;
  focusRound?: { roundIndex: number; token: number };
  canvasFullscreen?: boolean;
  onExitFullscreen?: () => void;
}

export function FlowCanvas(props: Props) {
  const { getNode, getNodesBounds, setCenter, setViewport } = useReactFlow();
  const nodesInitialized = useNodesInitialized();
  const shellRef = useRef<HTMLElement>(null);
  const previousBuild = useRef<string | undefined>(undefined);
  const positionBuild = useRef<string | undefined>(undefined);
  const manualPositions = useRef(new Map<string, { position: { x: number; y: number }; parentId?: string }>());
  const [detailLevel, setDetailLevel] = useState<"full" | "compact" | "overview">("overview");
  const layout = useMemo(() => buildHorizontalLayout(props.view, { buildId: String(props.view.header.id), expandedRounds: props.expandedRounds, expandedBranches: props.expandedBranches, expandedRetrievalAgents: props.expandedRetrievalAgents, detailLevel, onOpen: props.onOpen, onPrompt: props.onPrompt, onToggleRound: props.onToggleRound, onToggleBranch: props.onToggleBranch, onToggleRetrievalAgent: props.onToggleRetrievalAgent }), [props.view, props.expandedRounds, props.expandedBranches, props.expandedRetrievalAgents, detailLevel, props.onOpen, props.onPrompt, props.onToggleRound, props.onToggleBranch, props.onToggleRetrievalAgent]);
  const [nodes, setNodes, onNodesChange] = useNodesState<Node<CanvasNodeData>>([]);
  const handleMove: OnMove = useCallback((_, viewport) => {
    setDetailLevel((current) => {
      if (current === "full") return viewport.zoom < .74 ? "compact" : "full";
      if (current === "compact") {
        if (viewport.zoom >= .82) return "full";
        return viewport.zoom < .36 ? "overview" : "compact";
      }
      return viewport.zoom > .42 ? "compact" : "overview";
    });
  }, []);
  useEffect(() => {
    const buildId = String(props.view.header.id);
    if (positionBuild.current !== buildId) {
      positionBuild.current = buildId;
      manualPositions.current.clear();
    }
    setNodes(layout.nodes.map((node) => {
      const saved = manualPositions.current.get(node.id);
      return saved && saved.parentId === node.parentId ? { ...node, position: saved.position } : node;
    }));
  }, [layout.nodes, props.view.header.id, setNodes]);
  const rememberNodePosition = useCallback((_: unknown, node: Node<CanvasNodeData>) => {
    if (!node.draggable) return;
    manualPositions.current.set(node.id, { position: node.position, parentId: node.parentId });
  }, []);
  useEffect(() => {
    const buildId = String(props.view.header.id);
    if (!nodesInitialized || previousBuild.current === buildId) return;
    previousBuild.current = buildId;
    const frame = requestAnimationFrame(() => {
      const topLevelNodes = layout.nodes.filter((node) => !node.parentId);
      const canvasWidth = shellRef.current?.clientWidth || 0;
      const viewport = topLevelNodes.length && canvasWidth
        ? centeredOverviewViewport(getNodesBounds(topLevelNodes), canvasWidth)
        : INITIAL_VIEWPORT;
      void setViewport(viewport, { duration: 0 });
    });
    return () => cancelAnimationFrame(frame);
  }, [props.view.header.id, getNodesBounds, layout.nodes, nodesInitialized, setViewport]);
  useEffect(() => {
    if (!props.focusRound) return;
    const frame = requestAnimationFrame(() => {
      const target = getNode(`frame:round:${props.focusRound!.roundIndex}`) || getNode(`round:${props.focusRound!.roundIndex}:summary`);
      if (target) {
        const isFrame = target.id.startsWith("frame:");
        const width = isFrame ? Number(target.style?.width || 1980) : 320;
        const height = isFrame ? Number(target.style?.height || 720) : 360;
        void setCenter(target.position.x + width / 2, target.position.y + height / 2, { zoom: 1, duration: 220 });
      }
    });
    return () => cancelAnimationFrame(frame);
  }, [props.focusRound?.token, getNode, setCenter]);
  return <section ref={shellRef} className={`flowShell detail-${detailLevel} ${props.canvasFullscreen ? "mobileFullscreen" : ""}`} data-detail-level={detailLevel} aria-label="脚本构建横向运行画布">
    {props.canvasFullscreen ? <button type="button" className="exitFullscreen" onClick={props.onExitFullscreen}>返回轮次列表</button> : null}
    <ReactFlow nodes={nodes.map((node) => ({ ...node, selected: node.id === props.selectedId }))} edges={layout.edges} nodeTypes={nodeTypes} onNodesChange={onNodesChange} onNodeDrag={rememberNodePosition} onNodeDragStop={rememberNodePosition} defaultViewport={INITIAL_VIEWPORT} minZoom={MIN_CANVAS_ZOOM} maxZoom={1.5} onMove={handleMove} panOnScroll panOnScrollMode={PanOnScrollMode.Free} panOnScrollSpeed={.7} zoomOnScroll={false} zoomOnPinch nodesConnectable={false} elementsSelectable proOptions={{ hideAttribution: true }}>
      <Background variant={BackgroundVariant.Dots} gap={22} size={1.2} color="#343740" />
      <Controls position="bottom-left" showInteractive={false} />
    </ReactFlow>
  </section>;
}
