/**
 * Agent-specific logging types
 * Simplified 2-event model: lifecycle, iteration
 *
 * Design Philosophy:
 * - LIFECYCLE EVENTS: Structural checkpoints (initialization, iteration, completion)
 * - ITERATION EVENTS: Execution activities (reasoning, actions during iterations)
 */

import type { ExecutionLogLevel } from '../../base/logging'

// ============================================================================
// FORMAL TYPES
// ============================================================================

/**
 * Agent lifecycle stages
 * Universal checkpoints that apply to all agent executions
 */
export type AgentLifecycle = 'initialization' | 'iteration' | 'completion'

/**
 * Lifecycle stage status
 * Tracks progress through each lifecycle stage
 */
export type LifecycleStage = 'started' | 'completed' | 'failed'

/**
 * Iteration event types
 * Activities that occur during agent iterations
 */
export type IterationEventType = 'reasoning' | 'action' | 'tool-call'

// ============================================================================
// LIFECYCLE EVENTS (Structural Checkpoints)
// ============================================================================

/**
 * Base fields shared by all lifecycle events
 */
interface AgentLifecycleEventBase {
  type: 'agent'
  agentId: string
  lifecycle: AgentLifecycle
  sessionId?: string // Optional: only present when agent runs in session context
}

/**
 * Lifecycle started event - emitted when a phase begins
 * REQUIRED: startTime (phase has started, no end yet)
 */
export interface AgentLifecycleStartedEvent extends AgentLifecycleEventBase {
  stage: 'started'
  startTime: number // REQUIRED: Phase start timestamp
  iteration?: number // Only for 'iteration' lifecycle
}

/**
 * Lifecycle completed event - emitted when a phase succeeds
 * REQUIRED: startTime, endTime, duration (phase has finished successfully)
 */
export interface AgentLifecycleCompletedEvent extends AgentLifecycleEventBase {
  stage: 'completed'
  startTime: number // REQUIRED: Phase start timestamp
  endTime: number // REQUIRED: Phase end timestamp
  duration: number // REQUIRED: Calculated duration (endTime - startTime)
  iteration?: number // Only for 'iteration' lifecycle

  // Optional fields specific to certain lifecycles
  attempts?: number // Only for 'completion' lifecycle (tracks output generation attempts: 1 or 2)
  memorySize?: {
    sessionMemoryKeys: number
    historyEntries: number
  } // Only for 'completion' lifecycle (memory snapshot metadata)
}

/**
 * Lifecycle failed event - emitted when a phase fails
 * REQUIRED: startTime, endTime, duration, error (phase has finished with error)
 */
export interface AgentLifecycleFailedEvent extends AgentLifecycleEventBase {
  stage: 'failed'
  startTime: number // REQUIRED: Phase start timestamp
  endTime: number // REQUIRED: Phase end timestamp
  duration: number // REQUIRED: Calculated duration (endTime - startTime)
  error: string // REQUIRED: Error message
  iteration?: number // Only for 'iteration' lifecycle
}

/**
 * Union type for all lifecycle events
 * Discriminated by 'stage' field for type narrowing
 */
export type AgentLifecycleEvent = AgentLifecycleStartedEvent | AgentLifecycleCompletedEvent | AgentLifecycleFailedEvent

// ============================================================================
// ITERATION EVENTS (Execution Activities)
// ============================================================================

/**
 * Placeholder data for MVP
 * Will be typed per actionType in future
 */
export interface ActionPlaceholderData {
  message: string
}

/**
 * Iteration event - captures activities during agent iterations
 * Consolidates reasoning (LLM thought process) and actions (tool use, memory ops, etc.)
 */
export interface AgentIterationEvent {
  type: 'agent'
  agentId: string
  lifecycle: 'iteration' // Always iteration
  eventType: IterationEventType
  iteration: number
  sessionId?: string // Optional: only present when agent runs in session context

  // Timeline timing fields (v2 - Clean Break)
  startTime: number // Activity start timestamp
  endTime: number // Activity end timestamp
  duration: number // Calculated duration (endTime - startTime)

  // Conditional fields based on eventType
  output?: string // For reasoning events
  actionType?: string // For action events (tool-use, delegate, memory-write, etc.)
  data?: ActionPlaceholderData // For action events
}

/**
 * Tool call event - captures individual tool executions during iterations
 * Provides granular timing for each tool invocation
 */
export interface AgentToolCallEvent {
  type: 'agent'
  agentId: string
  lifecycle: 'iteration' // Always iteration
  eventType: 'tool-call' // Specific event type for tool calls
  iteration: number
  sessionId?: string // Optional: only present when agent runs in session context

  // Tool identification and timing
  toolName: string // Tool identifier
  startTime: number // Tool call start timestamp
  endTime: number // Tool call end timestamp
  duration: number // Calculated duration

  // Execution results
  success: boolean // Whether tool execution succeeded
  error?: string // Error message if failed
  input?: Record<string, unknown> // Tool input parameters
  output?: unknown // Tool output result
}

// ============================================================================
// UNION TYPES
// ============================================================================

/**
 * Union type for all agent log contexts
 * 3 event types total (lifecycle, iteration, tool-call)
 */
export type AgentLogContext = AgentLifecycleEvent | AgentIterationEvent | AgentToolCallEvent

/**
 * Agent execution log message (UI-specific interface)
 */
export interface AgentLogMessage {
  level: ExecutionLogLevel
  message: string
  timestamp: number
  context?: AgentLogContext
}

// ============================================================================
// TYPE GUARDS - Primary (2 total)
// ============================================================================

/**
 * Check if context is a lifecycle event
 */
export function isLifecycleEvent(ctx: AgentLogContext): ctx is AgentLifecycleEvent {
  return 'stage' in ctx && ctx.stage !== undefined
}

/**
 * Check if context is an iteration event
 */
export function isIterationEvent(ctx: AgentLogContext): ctx is AgentIterationEvent {
  return 'eventType' in ctx && ctx.eventType !== undefined
}

// ============================================================================
// TYPE GUARDS - Helpers (optional convenience)
// ============================================================================

/**
 * Check if lifecycle event is initialization
 */
export function isInitialization(evt: AgentLifecycleEvent): boolean {
  return evt.lifecycle === 'initialization'
}

/**
 * Check if lifecycle event is iteration
 */
export function isIteration(evt: AgentLifecycleEvent): boolean {
  return evt.lifecycle === 'iteration'
}

/**
 * Check if lifecycle event is completion
 */
export function isCompletion(evt: AgentLifecycleEvent): boolean {
  return evt.lifecycle === 'completion'
}

/**
 * Check if iteration event is reasoning
 */
export function isReasoningEvent(evt: AgentIterationEvent): boolean {
  return evt.eventType === 'reasoning'
}

/**
 * Check if iteration event is action
 */
export function isActionEvent(evt: AgentIterationEvent): boolean {
  return evt.eventType === 'action'
}

/**
 * Check if context is a tool call event
 */
export function isToolCallEvent(ctx: AgentLogContext): ctx is AgentToolCallEvent {
  return 'eventType' in ctx && ctx.eventType === 'tool-call'
}

/**
 * Check if action is tool-use
 */
export function isToolUseAction(evt: AgentIterationEvent): boolean {
  return evt.eventType === 'action' && evt.actionType === 'tool-use'
}

/**
 * Check if context has iteration information
 */
export function isIterationContext(ctx: AgentLogContext): boolean {
  return 'iteration' in ctx && typeof ctx.iteration === 'number'
}

// ============================================================================
// LOGGING UTILITIES
// ============================================================================

import type { IExecutionLogger } from '../../base/logging'

/**
 * Data for lifecycle 'started' events
 */
export interface AgentLifecycleStartedData {
  startTime: number
  iteration?: number
}

/**
 * Data for lifecycle 'completed' events
 */
export interface AgentLifecycleCompletedData {
  startTime: number
  endTime: number
  duration: number
  iteration?: number
  attempts?: number
  memorySize?: {
    sessionMemoryKeys: number
    historyEntries: number
  }
}

/**
 * Data for lifecycle 'failed' events
 */
export interface AgentLifecycleFailedData {
  startTime: number
  endTime: number
  duration: number
  error: string
  iteration?: number
}

/**
 * Scoped logger for agent execution
 * Captures logger and agentId to eliminate repetitive parameter passing
 *
 * Type-safe lifecycle logging with stage-specific required fields
 */
export interface AgentScopedLogger {
  lifecycle(lifecycle: AgentLifecycle, stage: 'started', data: AgentLifecycleStartedData): void
  lifecycle(lifecycle: AgentLifecycle, stage: 'completed', data: AgentLifecycleCompletedData): void
  lifecycle(lifecycle: AgentLifecycle, stage: 'failed', data: AgentLifecycleFailedData): void
  reasoning(output: string, iteration: number, startTime: number, endTime: number, duration: number): void
  action(
    actionType: string,
    message: string,
    iteration: number,
    startTime: number,
    endTime: number,
    duration: number
  ): void
  toolCall(
    toolName: string,
    iteration: number,
    startTime: number,
    endTime: number,
    duration: number,
    success: boolean,
    error?: string,
    input?: unknown,
    output?: unknown
  ): void
}

/**
 * Create a scoped logger bound to specific agent and logger instance
 * This eliminates the need to pass logger and agentId to every logging call
 *
 * @param logger - Execution logger instance
 * @param agentId - Agent identifier
 * @param sessionId - Optional session identifier (when agent runs in session context)
 * @returns Scoped logger with simplified API
 */
export function createAgentLogger(logger: IExecutionLogger, agentId: string, sessionId?: string): AgentScopedLogger {
  return {
    lifecycle(
      lifecycle: AgentLifecycle,
      stage: LifecycleStage,
      data: AgentLifecycleStartedData | AgentLifecycleCompletedData | AgentLifecycleFailedData
    ): void {
      // Build stage-specific event using discriminated union
      let event: AgentLifecycleEvent

      if (stage === 'started') {
        const startedData = data as AgentLifecycleStartedData
        event = {
          type: 'agent',
          agentId,
          lifecycle,
          stage: 'started',
          startTime: startedData.startTime,
          ...(sessionId && { sessionId }),
          ...(startedData.iteration !== undefined && { iteration: startedData.iteration })
        }
      } else if (stage === 'completed') {
        const completedData = data as AgentLifecycleCompletedData
        event = {
          type: 'agent',
          agentId,
          lifecycle,
          stage: 'completed',
          startTime: completedData.startTime,
          endTime: completedData.endTime,
          duration: completedData.duration,
          ...(sessionId && { sessionId }),
          ...(completedData.iteration !== undefined && { iteration: completedData.iteration }),
          ...(completedData.attempts !== undefined && { attempts: completedData.attempts }),
          ...(completedData.memorySize && { memorySize: completedData.memorySize })
        }
      } else {
        // stage === 'failed'
        const failedData = data as AgentLifecycleFailedData
        event = {
          type: 'agent',
          agentId,
          lifecycle,
          stage: 'failed',
          startTime: failedData.startTime,
          endTime: failedData.endTime,
          duration: failedData.duration,
          error: failedData.error,
          ...(sessionId && { sessionId }),
          ...(failedData.iteration !== undefined && { iteration: failedData.iteration })
        }
      }

      const level = stage === 'failed' ? 'error' : 'info'
      const iterationText = 'iteration' in event && event.iteration ? ` (iteration ${event.iteration})` : ''
      const message = `${lifecycle} ${stage}${iterationText}`
      logger[level](message, event)
    },

    reasoning(output: string, iteration: number, startTime: number, endTime: number, duration: number): void {
      const event: AgentIterationEvent = {
        type: 'agent',
        agentId,
        lifecycle: 'iteration',
        eventType: 'reasoning',
        iteration,
        output,
        startTime,
        endTime,
        duration,
        ...(sessionId && { sessionId }) // Include sessionId if present
      }
      logger.info('reasoning', event)
    },

    action(
      actionType: string,
      message: string,
      iteration: number,
      startTime: number,
      endTime: number,
      duration: number
    ): void {
      const event: AgentIterationEvent = {
        type: 'agent',
        agentId,
        lifecycle: 'iteration',
        eventType: 'action',
        iteration,
        actionType,
        startTime,
        endTime,
        duration,
        data: { message },
        ...(sessionId && { sessionId }) // Include sessionId if present
      }
      logger.info('action', event)
    },

    toolCall(
      toolName: string,
      iteration: number,
      startTime: number,
      endTime: number,
      duration: number,
      success: boolean,
      error?: string,
      input?: unknown,
      output?: unknown
    ): void {
      const event: AgentToolCallEvent = {
        type: 'agent',
        agentId,
        lifecycle: 'iteration',
        eventType: 'tool-call',
        iteration,
        toolName,
        startTime,
        endTime,
        duration,
        success,
        ...(error && { error }),
        ...(input !== undefined &&
          input !== null &&
          typeof input === 'object' &&
          !Array.isArray(input) && { input: input as Record<string, unknown> }),
        ...(output !== undefined && { output }),
        ...(sessionId && { sessionId }) // Include sessionId if present
      }
      logger.info(`tool-call: ${toolName}`, event)
    }
  }
}
