import { useState, useEffect, useCallback, useRef } from 'react';
import { useApiRequest } from '../useApi';
import {
  type Workflow,
  type WorkflowMessage,
  type WorkflowLog,
  type StartWorkflowRequest,
  fetchWorkflow as fetchWorkflowApi,
  fetchChatData
} from '../../api/workflowApi';
import { useWorkflowOperations } from './useWorkflowOperations';
import { sortMessages, sortLogs } from './playgroundUtils';
import { useWorkflowPolling } from './useWorkflowPolling';

interface UnifiedChatDataItem {
  type: 'message' | 'log' | 'stat';
  item: WorkflowMessage | WorkflowLog | any;
  createdAt: number;
}

/**
 * =============================================================================
 * WORKFLOW LIFECYCLE STATE MACHINE
 * =============================================================================
 * 
 * WORKFLOW STATUS (from Backend):
 *   • idle      - No workflow
 *   • running   - Workflow is processing
 *   • completed - Round finished (Backend processed "last" message)
 *   • stopped   - User stopped the workflow
 *   • failed    - Error occurred
 * 
 * UI FLAG:
 *   • hasRenderedLastMessage: boolean
 *     - true:  "last" message was rendered in UI
 *     - false: "last" message not yet in UI
 * 
 * POLLING LOGIC:
 *   POLL ACTIVE when:
 *     status === 'running'
 *     OR (status === 'completed' AND !hasRenderedLastMessage)
 * 
 *   POLL STOPS when:
 *     status === 'stopped'
 *     OR status === 'failed'
 *     OR hasRenderedLastMessage === true
 * 
 * TRANSITIONS:
 *   [Send Button] (from any status):
 *     → hasRenderedLastMessage = false (new round starts)
 *     → afterTimestamp = now
 *     → Start polling
 * 
 *   [Load Workflow]:
 *     → Load all data
 *     → Check if last message has status="last"
 *     → If yes: hasRenderedLastMessage = true, no polling
 *     → If no AND status=running: Start polling
 * 
 *   [Message with status="last" rendered]:
 *     → hasRenderedLastMessage = true
 *     → Stop polling
 * 
 * =============================================================================
 */

export function useWorkflowLifecycle(instanceId: string) {
  // === STATE ===
  const [workflowId, setWorkflowId] = useState<string | null>(null);
  const [workflowStatus, setWorkflowStatus] = useState<string>('idle');
  const [currentRound, setCurrentRound] = useState<number | undefined>(undefined);
  const [messages, setMessages] = useState<WorkflowMessage[]>([]);
  const [logs, setLogs] = useState<WorkflowLog[]>([]);
  const [dashboardLogs, setDashboardLogs] = useState<WorkflowLog[]>([]);
  const [unifiedContentLogs, setUnifiedContentLogs] = useState<WorkflowLog[]>([]);
  const [latestStats, setLatestStats] = useState<{ priceUsd?: number; processingTime?: number; bytesSent?: number; bytesReceived?: number } | null>(null);
  
  // === REFS FOR SYNC ACCESS ===
  const statusRef = useRef<string>('idle');
  const lastRenderedTimestampRef = useRef<number | null>(null);
  const processedStatIdsRef = useRef<Set<string>>(new Set());
  const cumulativeStatsRef = useRef({ priceUsd: 0, processingTime: 0, bytesSent: 0, bytesReceived: 0 });
  
  // === KEY STATE MACHINE FLAG ===
  // This flag tracks if the UI has rendered a message with status="last"
  // Polling continues until this is true (even if backend status is "completed")
  const hasRenderedLastMessageRef = useRef<boolean>(false);
  const [hasRenderedLastMessage, setHasRenderedLastMessage] = useState<boolean>(false);
  
  // Flag to prevent useEffect from stopping polling during active workflow start
  const isStartingWorkflowRef = useRef<boolean>(false);
  
  // === HOOKS ===
  const { startWorkflow, stopWorkflow, startingWorkflow, stoppingWorkflows } = useWorkflowOperations();
  const { request } = useApiRequest();
  const pollingController = useWorkflowPolling();
  const pollingControllerRef = useRef(pollingController);
  pollingControllerRef.current = pollingController;

  // === HELPER: Update workflow status ===
  const updateWorkflowStatus = useCallback((newStatus: string) => {
    statusRef.current = newStatus;
    setWorkflowStatus(newStatus);
    console.log('📍 Status updated to:', newStatus);
  }, []);

  // === HELPER: Convert backend log format to frontend format ===
  const convertLogToFrontendFormat = useCallback((log: any): WorkflowLog => {
    return {
      id: log.id,
      workflowId: log.workflowId || workflowId || '',
      message: log.message || '',
      type: log.type || 'info',
      timestamp: log.timestamp || log.createdAt || Date.now(),
      status: log.status || 'running',
      progress: log.progress !== undefined && log.progress !== null ? log.progress : undefined,
      performance: log.performance,
      operationId: log.operationId || null,
      parentId: log.parentId || null
    };
  }, [workflowId]);

  // === CORE: Process unified chat data ===
  const processUnifiedChatData = useCallback((chatData: { messages: WorkflowMessage[]; logs: WorkflowLog[]; stats: any[] }) => {
    console.log('🔄 Processing chat data:', {
      messages: chatData.messages?.length || 0,
      logs: chatData.logs?.length || 0,
      stats: chatData.stats?.length || 0
    });
    
    // Build unified timeline
    const timeline: UnifiedChatDataItem[] = [];

    // Add messages
    (chatData.messages || []).forEach((message: WorkflowMessage) => {
      timeline.push({
        type: 'message',
        item: message,
        createdAt: message.publishedAt || message.timestamp || Date.now()
      });
    });

    // Add logs
    (chatData.logs || []).forEach((log: any) => {
      timeline.push({
        type: 'log',
        item: log,
        createdAt: log.timestamp || log.createdAt || Date.now()
      });
    });

    // Add stats
    const rawStats = chatData.stats || [];
    rawStats.forEach((stat: any) => {
      timeline.push({
        type: 'stat',
        item: stat,
        createdAt: stat._createdAt || stat.createdAt || Date.now()
      });
    });

    // Sort chronologically
    timeline.sort((a, b) => a.createdAt - b.createdAt);

    // Update lastRenderedTimestamp
    if (timeline.length > 0) {
      lastRenderedTimestampRef.current = timeline[timeline.length - 1].createdAt;
    }

    // === CHECK FOR "LAST" MESSAGE ===
    // This is the key state machine logic: detect when a "last" message arrives
    let foundLastMessage = false;
    
    timeline.forEach((item) => {
      if (item.type === 'message') {
        const message = item.item as WorkflowMessage;
        if ((message as any).status === 'last') {
          foundLastMessage = true;
          console.log('🏁 Found "last" message:', message.id);
        }
      }
    });

    // === STATE MACHINE: Handle "last" message ===
    if (foundLastMessage && !hasRenderedLastMessageRef.current) {
      console.log('🛑 "last" message detected - stopping polling');
      hasRenderedLastMessageRef.current = true;
      setHasRenderedLastMessage(true);
      pollingControllerRef.current.stopPolling();
    }

    // === UPDATE MESSAGES STATE ===
    setMessages(prevMessages => {
      const newMessages: WorkflowMessage[] = [...prevMessages];
      let hasChanges = false;
      
      timeline.forEach((item) => {
        if (item.type === 'message') {
          const message = item.item as WorkflowMessage;
          if (!message || !message.id) return;
          
          const existingIndex = newMessages.findIndex(m => m.id === message.id);
          if (existingIndex >= 0) {
            newMessages[existingIndex] = message;
            hasChanges = true;
          } else {
            newMessages.push(message);
            hasChanges = true;
          }
        }
      });

      if (hasChanges || timeline.some(item => item.type === 'message')) {
        return [...newMessages].sort(sortMessages);
      }
      return prevMessages;
    });

    // === UPDATE DASHBOARD LOGS (with operationId) ===
    setDashboardLogs(prevLogs => {
      const newLogs: WorkflowLog[] = [...prevLogs];
      let hasChanges = false;
      
      timeline.forEach((item) => {
        if (item.type === 'log') {
          const frontendLog = convertLogToFrontendFormat(item.item);
          if (frontendLog.operationId) {
            const existingIndex = newLogs.findIndex(l => l.id === frontendLog.id);
            if (existingIndex >= 0) {
              if (JSON.stringify(newLogs[existingIndex]) !== JSON.stringify(frontendLog)) {
                newLogs[existingIndex] = frontendLog;
                hasChanges = true;
              }
            } else {
              newLogs.push(frontendLog);
              hasChanges = true;
            }
          }
        }
      });

      return hasChanges ? [...newLogs].sort(sortLogs) : prevLogs;
    });

    // === UPDATE UNIFIED CONTENT LOGS (without operationId) ===
    setUnifiedContentLogs(prevLogs => {
      const newLogs: WorkflowLog[] = [...prevLogs];
      let hasChanges = false;
      
      timeline.forEach((item) => {
        if (item.type === 'log') {
          const frontendLog = convertLogToFrontendFormat(item.item);
          if (!frontendLog.operationId) {
            const existingIndex = newLogs.findIndex(l => l.id === frontendLog.id);
            if (existingIndex >= 0) {
              if (JSON.stringify(newLogs[existingIndex]) !== JSON.stringify(frontendLog)) {
                newLogs[existingIndex] = frontendLog;
                hasChanges = true;
              }
            } else {
              newLogs.push(frontendLog);
              hasChanges = true;
            }
          }
        }
      });

      return hasChanges ? [...newLogs].sort(sortLogs) : prevLogs;
    });

    // === UPDATE COMBINED LOGS ===
    setLogs(prevLogs => {
      const allLogs: WorkflowLog[] = [...prevLogs];
      
      timeline.forEach((item) => {
        if (item.type === 'log') {
          const frontendLog = convertLogToFrontendFormat(item.item);
          const existingIndex = allLogs.findIndex(l => l.id === frontendLog.id);
          if (existingIndex >= 0) {
            allLogs[existingIndex] = frontendLog;
          } else {
            allLogs.push(frontendLog);
          }
        }
      });

      return [...allLogs].sort(sortLogs);
    });

    // === PROCESS STATS ===
    const statsItems = timeline.filter(item => item.type === 'stat');
    
    if (statsItems.length > 0) {
      let hasNewStats = false;
      
      statsItems.forEach(statItem => {
        const statData = statItem.item;
        const statId = statData?.id;
        
        if (statId && processedStatIdsRef.current.has(statId)) {
          return; // Skip already processed
        }
        
        if (statData) {
          hasNewStats = true;
          if (statId) {
            processedStatIdsRef.current.add(statId);
          }
          
          // Accumulate stats
          const price = statData.priceCHF ?? statData.priceUsd ?? 0;
          if (price > 0) cumulativeStatsRef.current.priceUsd += price;
          if (statData.processingTime) cumulativeStatsRef.current.processingTime += statData.processingTime;
          if (statData.bytesSent) cumulativeStatsRef.current.bytesSent += statData.bytesSent;
          if (statData.bytesReceived) cumulativeStatsRef.current.bytesReceived += statData.bytesReceived;
        }
      });
      
      if (hasNewStats) {
        setLatestStats({
          priceUsd: cumulativeStatsRef.current.priceUsd,
          processingTime: cumulativeStatsRef.current.processingTime,
          bytesSent: cumulativeStatsRef.current.bytesSent,
          bytesReceived: cumulativeStatsRef.current.bytesReceived
        });
      }
    }
  }, [convertLogToFrontendFormat]);

  // === POLLING FUNCTION ===
  const pollWorkflowData = useCallback(async (id: string) => {
    try {
      const afterTimestamp = lastRenderedTimestampRef.current || undefined;

      // Fetch workflow status
      const workflowData = await fetchWorkflowApi(request, id).catch(() => null);
      
      if (workflowData) {
        const status = workflowData.status || 'idle';
        const round = workflowData.currentRound;
        
        updateWorkflowStatus(status);
        if (round !== undefined) setCurrentRound(round);
        
        // === STATE MACHINE: Check if polling should stop based on status ===
        if (status === 'stopped' || status === 'failed') {
          console.log(`🛑 Workflow ${status} - stopping polling immediately`);
          pollingControllerRef.current.stopPolling();
          return;
        }
      }

      // Fetch chat data
      const chatData = await fetchChatData(request, instanceId, id, afterTimestamp);
      
      console.log('📊 Polled chat data:', {
        messages: chatData.messages?.length || 0,
        logs: chatData.logs?.length || 0,
        stats: chatData.stats?.length || 0,
        afterTimestamp
      });
      
      // Process data (this will detect "last" message and stop polling if found)
      processUnifiedChatData(chatData);
      
    } catch (error) {
      console.error('❌ Polling error:', error);
    }
  }, [request, instanceId, updateWorkflowStatus, processUnifiedChatData]);

  // === POLLING CONTROL EFFECT ===
  useEffect(() => {
    if (!workflowId) {
      pollingControllerRef.current.stopPolling();
      return;
    }

    // Skip if we're actively starting a workflow - handleStartWorkflow manages polling
    if (isStartingWorkflowRef.current) {
      console.log('📍 Polling decision: Skipping - workflow start in progress');
      return;
    }

    // === STATE MACHINE: Determine if polling should be active ===
    // Use ref for immediate value (state may be stale)
    const hasLastMessage = hasRenderedLastMessageRef.current;
    
    const shouldPoll = 
      workflowStatus === 'running' || 
      (workflowStatus === 'completed' && !hasLastMessage);
    
    const shouldStopImmediately = 
      workflowStatus === 'stopped' || 
      workflowStatus === 'failed' ||
      hasLastMessage;

    console.log('📍 Polling decision:', { 
      workflowStatus, 
      hasRenderedLastMessage: hasLastMessage,
      shouldPoll,
      shouldStopImmediately
    });

    if (shouldPoll) {
      pollingControllerRef.current.startPolling(workflowId, pollWorkflowData);
    } else if (shouldStopImmediately) {
      pollingControllerRef.current.stopPolling();
    }

    return () => {
      pollingControllerRef.current.stopPolling();
    };
  }, [workflowStatus, workflowId, hasRenderedLastMessage, pollWorkflowData]);

  // === START WORKFLOW (Send Button) ===
  const handleStartWorkflow = useCallback(async (
    workflowData: StartWorkflowRequest,
    options?: { workflowId?: string; workflowMode?: 'Dynamic' | 'Automation' }
  ) => {
    try {
      // Set flag to prevent useEffect from interfering during start
      isStartingWorkflowRef.current = true;
      
      const result = await startWorkflow(instanceId, workflowData, options);
      
      if (result.success && result.data) {
        const workflow = result.data as Workflow;
        
        // === STATE MACHINE: New round starts ===
        console.log('🚀 Starting workflow:', workflow.id);
        
        // Reset state for new round - MUST update refs BEFORE state
        hasRenderedLastMessageRef.current = false;
        
        // Set afterTimestamp to NOW - only poll for new data
        lastRenderedTimestampRef.current = Date.now();
        
        // Start polling immediately (before state updates trigger useEffect)
        pollingControllerRef.current.startPolling(workflow.id, pollWorkflowData);
        
        // Now update state (will trigger re-renders)
        setWorkflowId(workflow.id);
        setHasRenderedLastMessage(false);
        updateWorkflowStatus(workflow.status || 'running');
        
        // Clear the starting flag after a short delay to allow React to settle
        setTimeout(() => {
          isStartingWorkflowRef.current = false;
        }, 100);
        
        return { success: true, data: result.data };
      } else {
        isStartingWorkflowRef.current = false;
        return { success: false, error: result.error || 'Failed to start workflow' };
      }
    } catch (error: any) {
      isStartingWorkflowRef.current = false;
      return { success: false, error: error.message || 'Failed to start workflow' };
    }
  }, [instanceId, startWorkflow, updateWorkflowStatus, pollWorkflowData]);

  // === STOP WORKFLOW ===
  const handleStopWorkflow = useCallback(async () => {
    if (!workflowId) {
      return { success: false, error: 'No workflow to stop' };
    }
    
    try {
      const result = await stopWorkflow(instanceId, workflowId);
      
      if (result.success) {
        updateWorkflowStatus('stopped');
        pollingControllerRef.current.stopPolling();
        return { success: true };
      } else {
        return { success: false, error: result.error || 'Failed to stop workflow' };
      }
    } catch (error: any) {
      return { success: false, error: error.message || 'Failed to stop workflow' };
    }
  }, [instanceId, workflowId, stopWorkflow, updateWorkflowStatus]);

  // === RESET WORKFLOW ===
  const resetWorkflow = useCallback(() => {
    console.log('🔄 Resetting workflow state');
    
    setWorkflowId(null);
    updateWorkflowStatus('idle');
    setCurrentRound(undefined);
    setMessages([]);
    setLogs([]);
    setDashboardLogs([]);
    setUnifiedContentLogs([]);
    setLatestStats(null);
    
    // Reset refs
    lastRenderedTimestampRef.current = null;
    processedStatIdsRef.current.clear();
    cumulativeStatsRef.current = { priceUsd: 0, processingTime: 0, bytesSent: 0, bytesReceived: 0 };
    hasRenderedLastMessageRef.current = false;
    setHasRenderedLastMessage(false);
    
    pollingControllerRef.current.stopPolling();
  }, [updateWorkflowStatus]);

  // === SELECT/LOAD WORKFLOW ===
  const selectWorkflow = useCallback(async (workflowIdToSelect: string) => {
    try {
      console.log('📥 Loading workflow:', workflowIdToSelect);
      
      // Reset state
      setWorkflowId(workflowIdToSelect);
      lastRenderedTimestampRef.current = null;
      processedStatIdsRef.current.clear();
      cumulativeStatsRef.current = { priceUsd: 0, processingTime: 0, bytesSent: 0, bytesReceived: 0 };
      hasRenderedLastMessageRef.current = false;
      setHasRenderedLastMessage(false);
      
      // Fetch workflow data
      const workflowData = await fetchWorkflowApi(request, workflowIdToSelect).catch(() => null);
      
      if (!workflowData) {
        setMessages([]);
        setLogs([]);
        setDashboardLogs([]);
        setUnifiedContentLogs([]);
        setLatestStats(null);
        updateWorkflowStatus('idle');
        return;
      }
      
      const status = workflowData.status || 'idle';
      const round = workflowData.currentRound;
      
      updateWorkflowStatus(status);
      if (round !== undefined) setCurrentRound(round);
      
      // Fetch all chat data (no afterTimestamp = get everything)
      try {
        const chatData = await fetchChatData(request, instanceId, workflowIdToSelect, undefined);
        console.log('📥 Loaded chat data:', {
          messages: chatData.messages?.length || 0,
          logs: chatData.logs?.length || 0,
          stats: chatData.stats?.length || 0
        });
        
        // === STATE MACHINE: Check if last message has status="last" ===
        const allMessages = chatData.messages || [];
        const sortedMessages = [...allMessages].sort((a, b) => {
          const aTime = a.publishedAt || a.timestamp || 0;
          const bTime = b.publishedAt || b.timestamp || 0;
          return bTime - aTime; // Sort descending (newest first)
        });
        
        const lastMessage = sortedMessages[0];
        const lastMessageStatus = lastMessage ? (lastMessage as any).status : null;
        
        console.log('📍 Last message status:', lastMessageStatus);
        
        if (lastMessageStatus === 'last') {
          // Round is complete - don't start polling
          hasRenderedLastMessageRef.current = true;
          setHasRenderedLastMessage(true);
          console.log('✅ Workflow round complete - no polling needed');
        } else if (status === 'running') {
          // Workflow is running - polling will start via useEffect
          console.log('🔄 Workflow is running - polling will start');
        }
        
        // Process the data
        processUnifiedChatData(chatData);
        
      } catch (error) {
        console.warn('⚠️ Failed to fetch chat data:', error);
        updateWorkflowStatus('idle');
      }
      
    } catch (error) {
      console.error('❌ Error selecting workflow:', error);
    }
  }, [request, instanceId, updateWorkflowStatus, processUnifiedChatData]);

  // === EXPOSE STATUS SETTER FOR OPTIMISTIC UPDATES ===
  const setWorkflowStatusOptimistic = useCallback((status: string) => {
    updateWorkflowStatus(status);
  }, [updateWorkflowStatus]);

  // === COMPUTED VALUES ===
  const isRunning = workflowStatus === 'running';
  const isStopping = workflowId ? stoppingWorkflows.has(workflowId) : false;

  return {
    workflowId,
    workflowStatus,
    currentRound,
    isRunning,
    isStopping,
    startingWorkflow,
    messages,
    logs,
    dashboardLogs,
    unifiedContentLogs,
    latestStats,
    hasRenderedLastMessage,
    startWorkflow: handleStartWorkflow,
    stopWorkflow: handleStopWorkflow,
    resetWorkflow,
    selectWorkflow,
    setWorkflowStatusOptimistic
  };
}
