import React, { useCallback, useContext, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { MainMenu } from "../components/dashboard/MainMenu";
import { Stack, Box } from "@mui/material";
import { Recordings } from "../components/robot/Recordings";
import { Runs } from "../components/run/Runs";
import ProxyForm from '../components/proxy/ProxyForm';
import ApiKey from '../components/api/ApiKey';
import { AutoRobots } from '../components/robot/AutoRobots';
import { useGlobalInfoStore, useCacheInvalidation } from "../context/globalInfo";
import { createAndRunRecording, createRunForStoredRecording, CreateRunResponseWithQueue, interpretStoredRecording, notifyAboutAbort, scheduleStoredRecording } from "../api/storage";
import { io, Socket } from "socket.io-client";
import { stopRecording } from "../api/recording";
import { RunSettings } from "../components/run/RunSettings";
import { ScheduleSettings } from "../components/robot/pages/ScheduleSettingsPage";
import { apiUrl } from "../apiConfig";
import { useNavigate } from 'react-router-dom';
import { AuthContext } from '../context/auth';
import { useSocketStore } from '../context/socket';

interface MainPageProps {
  handleEditRecording: (id: string, fileName: string) => void;
  initialContent: string;
}

export interface CreateRunResponse {
  browserId: string;
  runId: string;
  robotMetaId: string;
}

export interface ScheduleRunResponse {
  message: string;
  runId: string;
}

export const MainPage = ({ handleEditRecording, initialContent }: MainPageProps) => {
  const { t } = useTranslation();
  const [content, setContent] = React.useState(initialContent);
  const [sockets, setSockets] = React.useState<Socket[]>([]);
  const [runningRecordingId, setRunningRecordingId] = React.useState('');
  const [runningRecordingName, setRunningRecordingName] = React.useState('');
  const [currentInterpretationLog, setCurrentInterpretationLog] = React.useState('');
  const [ids, setIds] = React.useState<CreateRunResponse>({
    browserId: '',
    runId: '',
    robotMetaId: ''
  });
  const [queuedRuns, setQueuedRuns] = React.useState<Set<string>>(new Set());

  let aborted = false;

  const { notify, setRerenderRuns, setRecordingId } = useGlobalInfoStore();
  const { invalidateRuns, addOptimisticRun } = useCacheInvalidation();
  const navigate  = useNavigate();

  React.useEffect(() => {
    setContent(initialContent);
  }, [initialContent]);

  const { state } = useContext(AuthContext);
  const { user } = state;

  const { connectToQueueSocket, disconnectQueueSocket } = useSocketStore();

  const abortRunHandler = (runId: string, robotName: string, browserId: string) => {
    notify('info', t('main_page.notifications.abort_initiated', { name: robotName }));

    aborted = true;
    
    notifyAboutAbort(runId).then(async (response) => {
      if (!response.success) {
        notify('error', t('main_page.notifications.abort_failed', { name: robotName }));
        setRerenderRuns(true);
        invalidateRuns();
        return;
      }
      
      if (response.isQueued) {
        setRerenderRuns(true);
        invalidateRuns();

        notify('success', t('main_page.notifications.abort_success', { name: robotName }));
        
        setQueuedRuns(prev => {
          const newSet = new Set(prev);
          newSet.delete(runId);
          return newSet;
        });
        
        return;
      }
      
      const abortSocket = io(`${apiUrl}/${browserId}`, {
        transports: ["websocket"],
        rejectUnauthorized: false
      });
      
      abortSocket.on('run-aborted', (abortData) => {
        if (abortData.runId === runId) {
          notify('success', t('main_page.notifications.abort_success', { name: abortData.robotName || robotName }));
          setRerenderRuns(true);
          invalidateRuns();
          abortSocket.disconnect();
        }
      });
      
      abortSocket.on('connect_error', (error) => {
        console.log('Abort socket connection error:', error);
        notify('error', t('main_page.notifications.abort_failed', { name: robotName }));
        setRerenderRuns(true);
        invalidateRuns();
        abortSocket.disconnect();
      });
    });
  }

  const setRecordingInfo = (id: string, name: string) => {
    setRunningRecordingId(id);
    setRecordingId(id);
    setRunningRecordingName(name);
  }

  const readyForRunHandler = useCallback((browserId: string, runId: string) => {
    interpretStoredRecording(runId).then(async (interpretation: boolean) => {
      if (!aborted) {
        if (interpretation) {
          // notify('success', t('main_page.notifications.interpretation_success', { name: runningRecordingName }));
        } else {
          notify('success', t('main_page.notifications.interpretation_failed', { name: runningRecordingName }));
          // destroy the created browser
          await stopRecording(browserId);
        }
      }
      setRunningRecordingName('');
      setCurrentInterpretationLog('');
      setRerenderRuns(true);
      invalidateRuns();
    })
  }, [runningRecordingName, aborted, currentInterpretationLog, notify, setRerenderRuns]);

  const debugMessageHandler = useCallback((msg: string) => {
    setCurrentInterpretationLog((prevState) =>
      prevState + '\n' + `[${new Date().toLocaleString()}] ` + msg);
  }, [currentInterpretationLog])

  const handleRunRecording = useCallback((settings: RunSettings) => {
    // Add optimistic run to cache immediately
    const optimisticRun = {
      id: runningRecordingId,
      runId: `temp-${Date.now()}`, // Temporary ID until we get the real one
      status: 'running',
      name: runningRecordingName,
      startedAt: new Date().toISOString(),
      finishedAt: '',
      robotMetaId: runningRecordingId,
      log: 'Starting...',
      isOptimistic: true
    };

    addOptimisticRun(optimisticRun);

    createAndRunRecording(runningRecordingId, settings).then((response: CreateRunResponseWithQueue) => {
      invalidateRuns();
      const { browserId, runId, robotMetaId, queued } = response;

      setIds({ browserId, runId, robotMetaId });
      navigate(`/runs/${robotMetaId}/run/${runId}`);
            
      if (queued) {
        setQueuedRuns(prev => new Set([...prev, runId]));
        notify('info', `Run queued: ${runningRecordingName}`);
      } else {
        const socket = io(`${apiUrl}/${browserId}`, {
          transports: ["websocket"],
          rejectUnauthorized: false
        });
        
        setSockets(sockets => [...sockets, socket]);
        
        socket.on('debugMessage', debugMessageHandler);
        socket.on('run-completed', (data) => {
          setRerenderRuns(true);
          invalidateRuns();
          
          const robotName = data.robotName;
          
          if (data.status === 'success') {
            notify('success', t('main_page.notifications.interpretation_success', { name: robotName }));
          } else {
            notify('error', t('main_page.notifications.interpretation_failed', { name: robotName }));
          }
        });
        
        socket.on('connect_error', (error) => {
          console.log('error', `Failed to connect to browser ${browserId}: ${error}`);
          notify('error', t('main_page.notifications.connection_failed', { name: runningRecordingName }));
        });

        socket.on('disconnect', (reason) => {
          console.log('warn', `Disconnected from browser ${browserId}: ${reason}`);
        });
        
        if (runId) {
          notify('info', t('main_page.notifications.run_started', { name: runningRecordingName }));
        } else {
          notify('error', t('main_page.notifications.run_start_failed', { name: runningRecordingName }));
        }
      }
      
      setContent('runs');
    }).catch((error: any) => {
      console.error('Error in createAndRunRecording:', error); // ✅ Debug log
    });

    return (socket: Socket) => {
      socket.off('debugMessage', debugMessageHandler);
      socket.off('run-completed');
      socket.off('connect_error');
      socket.off('disconnect');
    }
  }, [runningRecordingName, sockets, ids, debugMessageHandler, user?.id, t, notify, setRerenderRuns, setQueuedRuns, navigate, setContent, setIds, invalidateRuns, addOptimisticRun, runningRecordingId]);

  useEffect(() => {
    return () => {
      queuedRuns.clear();
    };
  }, []);

  const handleScheduleRecording = async (settings: ScheduleSettings) => {
    const { message, runId }: ScheduleRunResponse = await scheduleStoredRecording(runningRecordingId, settings);
    if (message === 'success') {
      notify('success', t('main_page.notifications.schedule_success', { name: runningRecordingName }));
    } else {
      notify('error', t('main_page.notifications.schedule_failed', { name: runningRecordingName }));
    }
    return message === 'success';
  }

  useEffect(() => {
    if (user?.id) {
      const handleRunStarted = (startedData: any) => {
        setRerenderRuns(true);
        invalidateRuns();
        
        const robotName = startedData.robotName || 'Unknown Robot';
        notify('info', t('main_page.notifications.run_started', { name: robotName }));
      };

      const handleRunCompleted = (completionData: any) => {
        setRerenderRuns(true);
        invalidateRuns(); // Invalidate cache to show completed run status
        
        if (queuedRuns.has(completionData.runId)) {
          setQueuedRuns(prev => {
            const newSet = new Set(prev);
            newSet.delete(completionData.runId);
            return newSet;
          });
        }
        
        const robotName = completionData.robotName || 'Unknown Robot';
        
        if (completionData.status === 'success') {
          notify('success', t('main_page.notifications.interpretation_success', { name: robotName }));
        } else {
          notify('error', t('main_page.notifications.interpretation_failed', { name: robotName }));
        }
      };

      const handleRunRecovered = (recoveredData: any) => {
        setRerenderRuns(true);
        invalidateRuns();
        
        if (queuedRuns.has(recoveredData.runId)) {
          setQueuedRuns(prev => {
            const newSet = new Set(prev);
            newSet.delete(recoveredData.runId);
            return newSet;
          });
        }
        
        const robotName = recoveredData.robotName || 'Unknown Robot';
        notify('error', t('main_page.notifications.interpretation_failed', { name: robotName }));
      };

      const handleRunScheduled = (scheduledData: any) => {
        setRerenderRuns(true);
        invalidateRuns();
      };
      
      connectToQueueSocket(user.id, handleRunCompleted, handleRunStarted, handleRunRecovered, handleRunScheduled);
      
      return () => {
        console.log('Disconnecting persistent queue socket for user:', user.id);
        disconnectQueueSocket();
      };
    }
  }, [user?.id, connectToQueueSocket, disconnectQueueSocket, t, setRerenderRuns, queuedRuns, setQueuedRuns]);

  const DisplayContent = () => {
    switch (content) {
      case 'robots':
        return <Recordings
          handleEditRecording={handleEditRecording}
          handleRunRecording={handleRunRecording}
          setRecordingInfo={setRecordingInfo}
          handleScheduleRecording={handleScheduleRecording}
        />;
      case 'runs':
        return <Runs
          currentInterpretationLog={currentInterpretationLog}
          abortRunHandler={abortRunHandler}
          runId={ids.runId}
          runningRecordingName={runningRecordingName}
        />;
      case 'proxy':
        return <ProxyForm />;
      case 'apikey':
        return <ApiKey />;
      case 'prebuilt-robots':
        return <AutoRobots />;
      default:
        return null;
    }
  }

return (
  <Box sx={{ display: 'flex', minHeight: 'calc(100vh - 64px)', width: '100%' }}>
    <Box sx={{ 
      width: 230,
      flexShrink: 0,
      position: 'sticky',
      top: 64,
      height: 'calc(100vh - 64px)', 
      overflowY: 'auto',
      zIndex: 1000 
    }}>
      <MainMenu value={content} handleChangeContent={setContent} />
    </Box>
    
    <Box sx={{ 
      flex: 1,
      minWidth: 0, 
      overflow: 'auto',
      minHeight: 'calc(100vh - 64px)',
      width: 'calc(100% - 250px)' 
    }}>
      {DisplayContent()}
    </Box>
  </Box>
)
}
