/**
 * Navigate Knowledge Action Executor
 * Loads knowledge nodes and registers their tools dynamically
 *
 * Features:
 * - Dynamic tool registration with duplicate checking
 * - Memory scoping (session vs task)
 * - Hierarchical navigation (flattens child nodes into main map)
 * - Cross-turn persistence (tracks loaded nodes in sessionMemory)
 */

import type { IterationContext } from '../core/types'
import type { NavigateKnowledgeAction } from './types'
import type { KnowledgeMapState } from '../knowledge-map/types'

/**
 * Execute a navigate-knowledge action
 * Loads knowledge node content and registers tools with the agent
 *
 * @param iterationContext - Agent execution context
 * @param action - Navigate knowledge action to execute
 */
export async function executeNavigateKnowledge(
  iterationContext: IterationContext,
  action: NavigateKnowledgeAction
): Promise<void> {
  const { knowledgeMap, toolRegistry, memoryManager, executionContext, iteration, logger } = iterationContext

  // Emit navigate knowledge event (before execution)
  await executionContext.onMessageEvent?.({
    type: 'agent:tool_call',
    toolName: 'navigate_knowledge',
    args: { nodeId: action.nodeId }
  })

  const startTime = Date.now()

  try {
    // Validate knowledge map exists
    if (!knowledgeMap) {
      throw new Error('Knowledge map not available - agent does not have knowledge navigation enabled')
    }

    // Look up knowledge node
    const node = knowledgeMap.nodes[action.nodeId]
    if (!node) {
      throw new Error(`Knowledge node '${action.nodeId}' not found in knowledge map`)
    }

    // Load knowledge content
    const content = await node.load(executionContext)

    // Cache prompt and set loaded flag (minimal caching)
    node.loaded = true
    node.prompt = content.prompt

    // Flatten child nodes into main knowledge map (hierarchical navigation)
    let childNodesCount = 0
    if (content.nodes && Object.keys(content.nodes).length > 0) {
      for (const [childId, childNode] of Object.entries(content.nodes)) {
        if (!knowledgeMap.nodes[childId]) {
          knowledgeMap.nodes[childId] = childNode
          childNodesCount++
        }
      }

      if (childNodesCount > 0) {
        logger.action(
          'knowledge-nodes-discovered',
          `Discovered ${childNodesCount} child nodes from '${action.nodeId}': ${Object.keys(content.nodes).join(', ')}`,
          iteration,
          startTime,
          startTime,
          0
        )
      }
    }

    // Register tools if provided (skip tools that are already registered)
    if (content.tools && content.tools.length > 0) {
      const newTools: string[] = []
      const skippedTools: string[] = []

      for (const tool of content.tools) {
        if (toolRegistry.has(tool.name)) {
          skippedTools.push(tool.name)
        } else {
          toolRegistry.set(tool.name, tool)
          newTools.push(tool.name)
        }
      }

      if (newTools.length > 0) {
        logger.action(
          'knowledge-tools-registered',
          `Registered ${newTools.length} tools from knowledge node '${action.nodeId}': ${newTools.join(', ')}`,
          iteration,
          startTime,
          startTime,
          0
        )
      }

      if (skippedTools.length > 0) {
        logger.action(
          'knowledge-tools-skipped',
          `Skipped ${skippedTools.length} already-registered tools: ${skippedTools.join(', ')}`,
          iteration,
          startTime,
          startTime,
          0
        )
      }
    }

    // Track loaded node in sessionMemory state for cross-turn persistence
    // Note: Prompt is now cached on node.content and serialized into system prompt
    // No separate sessionMemory/history storage needed
    const stateKey = 'knowledge-map-state'
    const existingState = memoryManager.get(stateKey)
    let state: KnowledgeMapState

    if (existingState) {
      try {
        state = JSON.parse(existingState) as KnowledgeMapState
      } catch {
        // Invalid state, create new
        state = { loadedNodes: [], version: 1 }
      }
    } else {
      state = { loadedNodes: [], version: 1 }
    }

    // Add node to loaded list if not already present
    if (!state.loadedNodes.includes(action.nodeId)) {
      state.loadedNodes.push(action.nodeId)
      memoryManager.set(stateKey, JSON.stringify(state))

      logger.action(
        'knowledge-state-updated',
        `Added '${action.nodeId}' to loaded nodes (total: ${state.loadedNodes.length})`,
        iteration,
        startTime,
        startTime,
        0
      )
    }

    const endTime = Date.now()
    const duration = endTime - startTime

    // Emit success event
    await executionContext.onMessageEvent?.({
      type: 'agent:tool_result',
      toolName: 'navigate_knowledge',
      success: true,
      result: {
        nodeId: action.nodeId,
        toolsLoaded: content.tools?.length ?? 0,
        childNodesDiscovered: childNodesCount,
        promptLength: content.prompt.length
      }
    })

    // Log tool call event (success)
    logger.toolCall(
      'navigate_knowledge',
      iteration,
      startTime,
      endTime,
      duration,
      true,
      undefined,
      { nodeId: action.nodeId },
      {
        nodeId: action.nodeId,
        toolsLoaded: content.tools?.length ?? 0,
        childNodesDiscovered: childNodesCount,
        promptLength: content.prompt.length
      }
    )

    // Build result message
    let resultMessage = `Knowledge node '${action.nodeId}' loaded successfully. ${content.tools?.length ?? 0} tools registered.`
    if (childNodesCount > 0) {
      resultMessage += ` ${childNodesCount} child nodes discovered.`
    }

    // Add success result to memory
    memoryManager.addToHistory({
      type: 'tool-result',
      content: resultMessage,
      turnNumber: executionContext.sessionTurnNumber ?? null,
      iterationNumber: iteration
    })
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error)
    const endTime = Date.now()
    const duration = endTime - startTime

    // Emit error event
    await executionContext.onMessageEvent?.({
      type: 'agent:tool_result',
      toolName: 'navigate_knowledge',
      success: false,
      error: errorMessage
    })

    // Log tool call event (failed)
    logger.toolCall(
      'navigate_knowledge',
      iteration,
      startTime,
      endTime,
      duration,
      false,
      errorMessage,
      { nodeId: action.nodeId },
      undefined
    )

    // Add error to memory
    memoryManager.addToHistory({
      type: 'error',
      content: `Error loading knowledge node '${action.nodeId}': ${errorMessage}`,
      turnNumber: executionContext.sessionTurnNumber ?? null,
      iterationNumber: iteration
    })
  }
}
