/**
 * Main SSE event handler factory
 * Creates a centralized handler that delegates to specialized handlers
 */

import { parseEventToMessage, shouldDisplayEvent } from "../EventParser";
import { normalizeEventType } from "../utils/eventNormalizer";
import { AnyMessage } from "../utils/messageAccumulator";
import {
  handleLLMChunk,
  handleToolCallStarted,
  handleToolCallCompleted,
  handleWorkflowCompleted,
  handleTaskCreated,
  handleError,
  handleA2UIEvent,
} from "./messageEventHandlers";
import {
  EVENT_LLM_CALL_CHUNK,
  EVENT_TOOL_CALL_STARTED,
  EVENT_TOOL_CALL_COMPLETED,
  EVENT_TOOL_CALL_FAILED,
  EVENT_WORKFLOW_COMPLETED,
  EVENT_WORKFLOW_FAILED,
  EVENT_TASK_FAILED,
  EVENT_CONNECTED,
  EVENT_TASK_CREATED,
  EVENT_ERROR,
  EVENT_MESSAGE,
  EVENT_A2UI_CREATE_SURFACE,
  EVENT_A2UI_UPDATE_COMPONENTS,
  EVENT_A2UI_UPDATE_DATA_MODEL,
  EVENT_A2UI_DELETE_SURFACE,
  EVENT_HUMAN_APPROVAL_REQUESTED,
  EVENT_HUMAN_APPROVAL_RECEIVED,
  EVENT_HUMAN_APPROVAL_DENIED,
} from "../constants/eventTypes";

export interface SSEEventHandlerOptions {
  /**
   * Current task ID (can be null)
   */
  currentTaskId: string | null;

  /**
   * Set the messages array
   */
  setMessages: React.Dispatch<React.SetStateAction<AnyMessage[]>>;

  /**
   * Set loading state
   */
  setIsLoading: (loading: boolean) => void;

  /**
   * Optional callback to track task lifecycle status from SSE events
   */
  setTaskLifecycleStatus?: (status: string) => void;

  /**
   * Set current task ID
   */
  setCurrentTaskId: (id: string | null) => void;

  /**
   * Callback when task is created
   */
  onTaskCreated?: (taskId: string) => void;

  /**
   * Callback when task is started
   */
  onTaskStarted?: (taskId: string) => void;

  /**
   * Callback when task is finished
   */
  onTaskFinished?: (taskId: string) => void;
}

/**
 * Creates an SSE event handler function
 *
 * This is the main event processing pipeline that:
 * 1. Normalizes event types
 * 2. Filters out non-displayable events
 * 3. Delegates to specialized handlers
 * 4. Handles system events (task_created, error, etc.)
 * 5. Parses and adds regular message events
 *
 * @param options - Handler configuration
 * @returns Event handler function
 *
 * @example
 * ```typescript
 * const handleSSEMessage = createSSEEventHandler({
 *   currentTaskId: null,
 *   setMessages,
 *   setIsLoading,
 *   setCurrentTaskId,
 *   onTaskStarted: (id) => router.push(`/tasks/${id}`)
 * });
 *
 * // Use with SSE connection
 * useSSE(sseUrl, { onMessage: handleSSEMessage });
 * ```
 */
export function createSSEEventHandler(
  options: SSEEventHandlerOptions
): (event: { type: string; data: any }) => void {
  const {
    currentTaskId,
    setMessages,
    setIsLoading,
    setTaskLifecycleStatus,
    setCurrentTaskId,
    onTaskCreated,
    onTaskStarted,
    onTaskFinished,
  } = options;

  return (event: { type: string; data: any }) => {
    // Get the actual event type from the data if available
    const actualEventType =
      event.data?.event_type || event.data?.original_event_type || event.type;

    // Handle generic "message" events that might be heartbeats or connection events
    if (actualEventType === EVENT_MESSAGE && !event.data?.event_type) {
      // This is likely a heartbeat or connection event - just return
      return;
    }

    // Normalize to canonical event type
    const cleanEventType = normalizeEventType(actualEventType);

    // Handle approval resolution - update existing approval message
    if (
      cleanEventType === EVENT_HUMAN_APPROVAL_RECEIVED ||
      cleanEventType === EVENT_HUMAN_APPROVAL_DENIED
    ) {
      const escalationId = event.data?.escalation_id || event.data?.original_data?.escalation_id;
      if (escalationId) {
        setMessages((prev) =>
          prev.map((msg) => {
            if (
              "type" in msg &&
              msg.type === "approval_request" &&
              (msg as any).data.escalation_id === escalationId
            ) {
              return {
                ...msg,
                data: {
                  ...(msg as any).data,
                  resolved: true,
                  approved: cleanEventType === EVENT_HUMAN_APPROVAL_RECEIVED,
                  deny_comment: event.data?.comment || event.data?.original_data?.comment,
                },
              };
            }
            return msg;
          })
        );
      }
      return;
    }

    // Check if this event should create a visible message
    if (!shouldDisplayEvent(cleanEventType)) {
      return;
    }

    // Special handling for LLM chunk events - accumulate instead of creating new messages
    if (cleanEventType === EVENT_LLM_CALL_CHUNK) {
      handleLLMChunk(event, setMessages);
      return;
    }

    // A2UI surface events — createSurface falls through to parseEventToMessage;
    // update/delete mutate existing surface messages in-place
    if (cleanEventType === EVENT_A2UI_CREATE_SURFACE) {
      const messageComponent = parseEventToMessage(cleanEventType, event.data);
      if (messageComponent) {
        setMessages((prev) => [...prev, messageComponent]);
      }
      return;
    }
    if (
      cleanEventType === EVENT_A2UI_UPDATE_COMPONENTS ||
      cleanEventType === EVENT_A2UI_UPDATE_DATA_MODEL ||
      cleanEventType === EVENT_A2UI_DELETE_SURFACE
    ) {
      handleA2UIEvent(cleanEventType, event, setMessages);
      return;
    }

    // Special handling for tool call events
    if (cleanEventType === EVENT_TOOL_CALL_STARTED) {
      handleToolCallStarted(event, setMessages);
      return;
    }

    if (
      cleanEventType === EVENT_TOOL_CALL_COMPLETED ||
      cleanEventType === EVENT_TOOL_CALL_FAILED
    ) {
      handleToolCallCompleted(event, setMessages);
      return;
    }

    // Clear any loading state FIRST - before message parsing
    if (
      cleanEventType === EVENT_WORKFLOW_COMPLETED ||
      cleanEventType === EVENT_WORKFLOW_FAILED ||
      cleanEventType === EVENT_TASK_FAILED
    ) {
      handleWorkflowCompleted(event, {
        setIsLoading,
        onTaskFinished,
        currentTaskId,
      });
    }

    if (cleanEventType === EVENT_WORKFLOW_COMPLETED) {
      setTaskLifecycleStatus?.("completed");
    } else if (cleanEventType === EVENT_WORKFLOW_FAILED || cleanEventType === EVENT_TASK_FAILED) {
      const errorText =
        String(event.data?.error || event.data?.message || event.data?.result?.error || "").toLowerCase();
      if (
        errorText.includes("insufficient balance") ||
        errorText.includes("no resource package") ||
        errorText.includes("quota exceeded")
      ) {
        setTaskLifecycleStatus?.("blocked");
      } else {
        setTaskLifecycleStatus?.("failed");
      }
    } else if (cleanEventType === "execution_paused") {
      setTaskLifecycleStatus?.("paused");
    } else if (cleanEventType === "execution_resumed") {
      setTaskLifecycleStatus?.("running");
    }

    // Handle special system events FIRST, before checking if they create visible messages
    switch (cleanEventType) {
      case EVENT_CONNECTED:
        break;

      case EVENT_TASK_CREATED:
        handleTaskCreated(event, {
          currentTaskId,
          setCurrentTaskId,
          onTaskCreated,
          onTaskStarted,
        });
        break;

      case EVENT_ERROR:
        handleError(setIsLoading);
        break;

      default:
        break;
    }

    // Parse event into message component for display
    const messageComponent = parseEventToMessage(cleanEventType, event.data);
    if (!messageComponent) {
      return;
    }

    // Add the new message component to the messages
    setMessages((prev) => [...prev, messageComponent]);
  };
}
