import { ApiRequestOptions } from '../hooks/useApi';
import api from '../api';
import { addCSRFTokenToHeaders, getCSRFToken, generateAndStoreCSRFToken } from '../utils/csrfUtils';
import { Message } from '../components/UiComponents/Messages/MessagesTypes';

// ============================================================================
// TYPES & INTERFACES
// ============================================================================

export interface UserInputRequest {
  input: string;
  workflowId?: string;
  files?: Array<{ id: string; name: string }>;
  metadata?: Record<string, any>;
}

export interface ChatbotWorkflow {
  id: string;
  mandateId: string;
  status: string;
  name?: string;
  currentRound?: number;
  currentTask?: number;
  currentAction?: number;
  startedAt?: number;
  lastActivity?: number;
  [key: string]: any;
}

export interface StartChatbotRequest {
  prompt: string;
  listFileId?: string[];
  userLanguage?: string;
  workflowId?: string;
  metadata?: Record<string, any>;
}

export interface StartChatbotResponse extends ChatbotWorkflow {
  // Workflow object returned from start endpoint
}

export interface ChatDataItem {
  type: 'message' | 'log' | 'stat' | 'document';
  createdAt: number;
  item: Message | any;
}

// Type for the request function passed to API functions
export type ApiRequestFunction = (options: ApiRequestOptions<any>) => Promise<any>;

// Type for SSE event handler
export type SSEEventHandler = (item: ChatDataItem) => void;

// ============================================================================
// API REQUEST FUNCTIONS
// ============================================================================

/**
 * Start a new chatbot workflow or continue an existing one with SSE streaming
 * Endpoint: POST /api/chatbot/start/stream
 * 
 * @param requestBody - Request body with prompt and optional workflowId
 * @param onEvent - Callback function called for each SSE event
 * @param onError - Optional error callback
 * @param onComplete - Optional completion callback
 * @returns Promise that resolves when stream completes
 */
export async function startChatbotStreamApi(
  requestBody: StartChatbotRequest,
  onEvent: SSEEventHandler,
  onError?: (error: Error) => void,
  onComplete?: () => void
): Promise<void> {
  try {
    // Prepare request body
    console.log('[startChatbotStreamApi] requestBody received:', JSON.stringify(requestBody, null, 2));
    
    const body: any = {
      prompt: requestBody.prompt,
      ...(requestBody.listFileId && requestBody.listFileId.length > 0 && { listFileId: requestBody.listFileId }),
      ...(requestBody.userLanguage && { userLanguage: requestBody.userLanguage }),
      ...(requestBody.metadata && { metadata: requestBody.metadata })
    };
    
    console.log('[startChatbotStreamApi] body being sent:', JSON.stringify(body, null, 2));

    // Add workflowId to query params if provided
    const url = requestBody.workflowId
      ? `/api/chatbot/start/stream?workflowId=${encodeURIComponent(requestBody.workflowId)}`
      : '/api/chatbot/start/stream';

    // Get base URL from api instance
    const baseURL = api.defaults.baseURL || '';
    const fullURL = baseURL + url;

    // Prepare headers with authentication and CSRF token
    const headers: Record<string, string> = {
      'Content-Type': 'application/json'
    };

    // Add auth token if available
    const authToken = localStorage.getItem('authToken');
    if (authToken) {
      headers['Authorization'] = `Bearer ${authToken}`;
    }

    // Add CSRF token for POST requests
    if (!getCSRFToken()) {
      generateAndStoreCSRFToken();
    }
    addCSRFTokenToHeaders(headers);

    // Use fetch for SSE streaming (POST with body)
    const response = await fetch(fullURL, {
      method: 'POST',
      headers,
      body: JSON.stringify(body),
      credentials: 'include' // Include cookies for authentication
    });

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
    }

    if (!response.body) {
      throw new Error('Response body is null');
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';

    try {
      while (true) {
        const { done, value } = await reader.read();

        if (done) {
          break;
        }

        // Decode chunk and add to buffer
        buffer += decoder.decode(value, { stream: true });

        // Process complete SSE messages
        const lines = buffer.split('\n');
        buffer = lines.pop() || ''; // Keep incomplete line in buffer

        for (const line of lines) {
          if (line.startsWith('data: ')) {
            try {
              const jsonStr = line.slice(6); // Remove 'data: ' prefix
              if (jsonStr.trim()) {
                const item: ChatDataItem = JSON.parse(jsonStr);
                onEvent(item);
              }
            } catch (parseError) {
              console.warn('Failed to parse SSE event:', line, parseError);
            }
          } else if (line.startsWith(':')) {
            // Comment/keepalive line, ignore
            continue;
          }
        }
      }

      // Process any remaining buffer content
      if (buffer.trim()) {
        const lines = buffer.split('\n');
        for (const line of lines) {
          if (line.startsWith('data: ')) {
            try {
              const jsonStr = line.slice(6);
              if (jsonStr.trim()) {
                const item: ChatDataItem = JSON.parse(jsonStr);
                onEvent(item);
              }
            } catch (parseError) {
              console.warn('Failed to parse SSE event:', line, parseError);
            }
          }
        }
      }

      if (onComplete) {
        onComplete();
      }
    } finally {
      reader.releaseLock();
    }
  } catch (error: any) {
    console.error('Error in startChatbotStreamApi:', error);
    if (onError) {
      onError(error instanceof Error ? error : new Error(String(error)));
    } else {
      throw error;
    }
  }
}

/**
 * Stop a running chatbot workflow
 * Endpoint: POST /api/chatbot/{workflowId}/stop
 */
export async function stopChatbotApi(
  request: ApiRequestFunction,
  workflowId: string
): Promise<ChatbotWorkflow> {
  const data = await request({
    url: `/api/chatbot/${workflowId}/stop`,
    method: 'post'
  });

  return data as ChatbotWorkflow;
}

/**
 * Get chatbot threads/workflows
 * Endpoint: GET /api/chatbot/threads
 */
export async function getChatbotThreadsApi(
  request: ApiRequestFunction,
  pagination?: { page?: number; pageSize?: number }
): Promise<{ items: ChatbotWorkflow[]; metadata: any }> {
  const paginationParam = pagination ? JSON.stringify(pagination) : undefined;
  const requestParams = paginationParam
    ? { pagination: paginationParam }
    : undefined;

  console.log(`[getChatbotThreadsApi] Fetching threads with params:`, requestParams);

  const data = await request({
    url: '/api/chatbot/threads',
    method: 'get',
    params: requestParams
  }) as any;

  console.log(`[getChatbotThreadsApi] Full response:`, JSON.stringify(data, null, 2));
  console.log(`[getChatbotThreadsApi] Response structure:`, {
    hasItems: !!data.items,
    itemsLength: Array.isArray(data.items) ? data.items.length : 'not an array',
    hasMetadata: !!data.metadata,
    metadataKeys: data.metadata ? Object.keys(data.metadata) : []
  });

  return {
    items: Array.isArray(data.items) ? data.items : [],
    metadata: data.metadata || {}
  };
}

/**
 * Get a specific chatbot thread/workflow with its chat data
 * Endpoint: GET /api/chatbot/threads?workflowId={id}
 * 
 * Backend returns: { workflow: ChatbotWorkflow, chatData: { items: ChatDataItem[] } }
 * 
 * @param request - API request function
 * @param workflowId - ID of the workflow to fetch
 * @returns Object containing workflow details and chatData with items array
 */
export async function getChatbotThreadApi(
  request: ApiRequestFunction,
  workflowId: string
): Promise<{ workflow: ChatbotWorkflow; chatData: { items: ChatDataItem[] } }> {
  console.log(`[getChatbotThreadApi] Fetching thread with workflowId: ${workflowId}`);
  
  const data = await request({
    url: '/api/chatbot/threads',
    method: 'get',
    params: { workflowId }
  }) as { workflow: ChatbotWorkflow; chatData: { items: ChatDataItem[] } };

  console.log(`[getChatbotThreadApi] Full response for workflowId ${workflowId}:`, JSON.stringify(data, null, 2));
  console.log(`[getChatbotThreadApi] Response structure:`, {
    hasWorkflow: !!data.workflow,
    workflowKeys: data.workflow ? Object.keys(data.workflow) : [],
    hasChatData: !!data.chatData,
    hasItems: !!data.chatData?.items,
    chatDataKeys: data.chatData ? Object.keys(data.chatData) : [],
    itemsLength: Array.isArray(data.chatData?.items) ? data.chatData.items.length : 'not an array',
    chatDataTypes: Array.isArray(data.chatData?.items) ? data.chatData.items.map((item: ChatDataItem) => item?.type).filter(Boolean) : []
  });

  return {
    workflow: data.workflow,
    chatData: data.chatData || { items: [] }
  };
}

/**
 * Delete a chatbot workflow
 * Endpoint: DELETE /api/chatbot/{workflowId}
 * 
 * @param request - API request function
 * @param workflowId - ID of the workflow to delete
 * @returns Success status
 */
export async function deleteChatbotWorkflowApi(
  request: ApiRequestFunction,
  workflowId: string
): Promise<boolean> {
  try {
    await request({
      url: `/api/chatbot/${workflowId}`,
      method: 'delete'
    });
    return true;
  } catch (error: any) {
    console.error('Error deleting chatbot workflow:', error);
    throw error;
  }
}

