import React, { useMemo } from 'react'
import type { Connection } from '@xyflow/react'
import type { AppNode, AppEdge } from '@/lib/nodeTypes'

export type ConnectionFrom = { nodeId: string; sourceHandle?: string } | null

/** Role of a node in the current connection path update: pushing data, receiving/loading, or just on path. */
export type ConnectionPathRole = 'trigger' | 'updating' | 'on-path'

export type FlowActions = {
    pasteAtViewportCenter: () => void
    fitView: () => void
}

export type FlowContextValue = {
    nodes: AppNode[]
    setNodes: (updater: AppNode[] | ((prev: AppNode[]) => AppNode[])) => void
    edges: AppEdge[]
    setEdges: (updater: AppEdge[] | ((prev: AppEdge[]) => AppEdge[])) => void
    renamingNodeId: string | null
    setRenamingNodeId: (id: string | null) => void
    /** Set when user starts dragging from an output handle; cleared on connect end. Used to highlight valid targets. */
    connectionFrom: ConnectionFrom
    setConnectionFrom: (v: ConnectionFrom) => void
    isValidConnection: (connection: Connection) => boolean
    /** Set by FlowKeyboardShortcuts so Node menubar can trigger paste / fit view. */
    flowActionsRef: React.MutableRefObject<FlowActions | null>
    /** When set, graph centers on this node and a fullscreen dialog shows the node. Cleared on close. */
    fullscreenNodeId: string | null
    setFullscreenNodeId: (id: string | null) => void
    /** Node ids currently updating (e.g. render loading, agent running). Only edges on those paths show the ant trail. */
    connectionPathUpdatingNodeIds: string[]
    /** Node ids that triggered the current update (e.g. variable/config that changed). Path is restricted to downstream(trigger) ∩ upstream(updating). */
    connectionPathTriggerNodeIds: string[]
    /** Call when this node's output changed and may trigger downstream updates (e.g. variable value, config content). */
    addConnectionPathTrigger: (nodeId: string) => void
    /** All node ids on the path of an update. Edges with both endpoints in this set animate. */
    connectionPathNodeIds: Set<string>
    /** Call when a path update starts for this node. Animation runs at least CONNECTION_PATH_UPDATE_MIN_MS. */
    startConnectionPathUpdate: (nodeId: string) => void
    /** Call when a path update ends for this node. If min duration not reached, animation continues until then. */
    endConnectionPathUpdate: (nodeId: string) => void
}

const FlowContext = React.createContext<FlowContextValue | null>(null)

export default FlowContext

/**
 * Returns this node's role in the current path update for styling (pushing vs receiving).
 * Use with BaseNode's connectionPathRole prop or data-path-role for CSS.
 */
export function useConnectionPathRole(nodeId: string | undefined): ConnectionPathRole | null {
  const ctx = React.useContext(FlowContext)
  return useMemo(() => {
    if (!nodeId) return null
    const triggers = ctx?.connectionPathTriggerNodeIds
    const updating = ctx?.connectionPathUpdatingNodeIds
    const path = ctx?.connectionPathNodeIds
    if (!path?.has(nodeId)) return null
    if (triggers?.includes(nodeId)) return 'trigger'
    if (updating?.includes(nodeId)) return 'updating'
    return 'on-path'
  }, [nodeId, ctx?.connectionPathTriggerNodeIds, ctx?.connectionPathUpdatingNodeIds, ctx?.connectionPathNodeIds])
}
