import React, { useState, useEffect, useRef } from "react";
import { Box, Typography, CircularProgress, Alert, Paper } from "@mui/material";
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import AccessTimeIcon from "@mui/icons-material/AccessTime";
import LogDisplay from "../LogDisplay";
import { useNavigate, useSearchParams } from "react-router-dom";
import API_CONFIG from "../../config/api";
import ErrorDisplay from "../common/ErrorDisplay";

// Durée de simulation en millisecondes pour les documents précalculés
const SIMULATION_DURATION = 80000; // 20 seconds

// Définir toutes les étapes du benchmark en séquence
const BENCHMARK_STEPS = [
  "configuration",
  "provider_check",
  "ingestion",
  "upload_ingest_to_hub",
  "summarization",
  "chunking",
  "single_shot_question_generation",
];

// Étiquettes des étapes pour l'affichage (noms plus conviviaux)
const STEP_LABELS = {
  configuration: "Configuration",
  provider_check: "Finding providers",
  ingestion: "Ingestion",
  upload_ingest_to_hub: "Upload to Hub",
  summarization: "Summarization",
  chunking: "Chunking",
  single_shot_question_generation: "Question generation",
  evaluation_provider_check: "Checking evaluation providers",
  evaluation: "Running evaluations",
  evaluation_saving_results: "Saving evaluation results",
};

// Messages de log simulés pour les documents précalculés
const SIMULATED_LOGS = [
  "[INFO] Initializing benchmark generation...",
  "[INFO] Generating base configuration file...",
  "[SUCCESS] Stage completed: configuration",
  "[INFO] Finding available providers for models...",
  "[SUCCESS] Stage completed: provider_check",
  "[INFO] Starting ingestion process...",
  "[SUCCESS] Stage completed: ingestion",
  "[INFO] Processing document content for upload...",
  "[SUCCESS] Stage completed: upload_ingest_to_hub",
  "[INFO] Generating document summary...",
  "[SUCCESS] Stage completed: summarization",
  "[INFO] Chunking content for better analysis...",
  "[SUCCESS] Stage completed: chunking",
  "[INFO] Generating single-shot questions...",
  "[SUCCESS] Stage completed: single_shot_question_generation",
  "[SUCCESS] Benchmark process completed successfully",
];

/**
 * Composant pour gérer la génération de benchmark et afficher les logs
 *
 * @param {Object} props - Propriétés du composant
 * @param {string} props.sessionId - ID de session pour le fichier uploadé
 * @param {boolean} props.isDefaultDocument - S'il s'agit d'un document précalculé
 * @param {Function} props.onComplete - Fonction à appeler lorsque la génération est terminée
 * @returns {JSX.Element} Composant de génération de benchmark
 */
const Generator = ({ sessionId, isDefaultDocument, onComplete }) => {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const isDefault =
    searchParams.get("isDefault") === "true" || isDefaultDocument;

  // États du composant
  const [generating, setGenerating] = useState(false);
  const [generationComplete, setGenerationComplete] = useState(false);
  const [generationLogs, setGenerationLogs] = useState([]);
  const [error, setError] = useState(null);
  const [currentPhase, setCurrentPhase] = useState("initializing");
  const [completedSteps, setCompletedSteps] = useState([]);
  const [activeStep, setActiveStep] = useState(1);
  const [elapsedTime, setElapsedTime] = useState(0);

  // Références pour les intervalles et timers
  const pollingIntervalRef = useRef(null);
  const timerIntervalRef = useRef(null);
  const startTimeRef = useRef(null);
  const simulationIntervalRef = useRef(null);
  const hasRedirectedRef = useRef(false);

  // Fonction pour réinitialiser les états de génération
  const resetGenerationStates = () => {
    setGenerating(true);
    setGenerationLogs([]);
    setError(null);
    setCurrentPhase("initializing");
    setCompletedSteps([]);
    setActiveStep(1);
  };

  // Fonction pour arrêter les intervalles
  const clearAllIntervals = () => {
    if (pollingIntervalRef.current) clearInterval(pollingIntervalRef.current);
    if (timerIntervalRef.current) clearInterval(timerIntervalRef.current);
    if (simulationIntervalRef.current)
      clearInterval(simulationIntervalRef.current);
  };

  // Fonction pour notifier la fin de la génération
  const notifyGenerationComplete = (success, logs, errorMsg = null) => {
    setGenerationComplete(true);
    clearAllIntervals();

    if (onComplete) {
      onComplete({
        success,
        sessionId,
        logs: logs || generationLogs,
        error: errorMsg,
      });
    }
  };

  // Démarrer la génération au montage du composant
  useEffect(() => {
    // Configurer l'heure de départ
    startTimeRef.current = Date.now();

    // Démarrer le timer
    timerIntervalRef.current = setInterval(() => {
      const timeElapsed = Math.floor(
        (Date.now() - startTimeRef.current) / 1000
      );
      setElapsedTime(timeElapsed);

      // Vérifier si le temps écoulé dépasse 5 minutes et que nous ne sommes pas en mode simulation
      if (timeElapsed > 300 && !isDefault && !generationComplete) {
        setError(
          "The benchmark generation is taking too long. The demo is currently under heavy load, please try again later."
        );
        notifyGenerationComplete(false, null, "Timeout error");
      }
    }, 1000);

    // Gestionnaire pour détecter quand la page redevient visible
    const handleVisibilityChange = () => {
      if (
        document.visibilityState === "visible" &&
        !isDefault &&
        !generationComplete
      ) {
        console.log("Page became visible, checking for missed steps...");

        // Forcer une nouvelle requête pour récupérer les logs
        const checkCurrentState = async () => {
          try {
            const progressResponse = await fetch(
              `${API_CONFIG.BASE_URL}/benchmark-progress/${sessionId}`
            );

            if (progressResponse.ok) {
              const progressResult = await progressResponse.json();
              if (progressResult.logs) {
                setGenerationLogs(progressResult.logs);
              }

              if (progressResult.is_completed) {
                notifyGenerationComplete(true, progressResult.logs);
              }
            }
          } catch (error) {
            console.error("Error checking for missed steps:", error);
          }
        };

        checkCurrentState();
      }
    };

    // Ajouter l'écouteur pour le changement de visibilité
    document.addEventListener("visibilitychange", handleVisibilityChange);

    // Lancer la simulation ou la génération
    if (isDefault) {
      simulateGeneration();
    } else {
      generateBenchmark();
    }

    // Nettoyer les intervalles et écouteurs lors du démontage
    return () => {
      clearAllIntervals();
      document.removeEventListener("visibilitychange", handleVisibilityChange);
    };
  }, [isDefault, sessionId, generationComplete, onComplete]);

  // Simuler la génération de benchmark pour les documents précalculés
  const simulateGeneration = () => {
    resetGenerationStates();

    // Variables de timing pour la simulation
    const totalSteps = SIMULATED_LOGS.length;
    const intervalPerStep = SIMULATION_DURATION / totalSteps;
    let currentStep = 0;

    // Fonction pour ajouter le prochain message de log
    const addNextLog = () => {
      if (currentStep < SIMULATED_LOGS.length) {
        const newLogs = [...generationLogs, SIMULATED_LOGS[currentStep]];
        setGenerationLogs(newLogs);
        currentStep++;

        // Vérifier si terminé
        if (currentStep >= SIMULATED_LOGS.length) {
          // Simulation terminée
          setTimeout(() => {
            setCurrentPhase("complete");
            notifyGenerationComplete(true, newLogs);
          }, 1000);
        }
      }
    };

    // Démarrer la simulation
    simulationIntervalRef.current = setInterval(addNextLog, intervalPerStep);
  };

  // Déterminer la phase actuelle et les étapes terminées en fonction des logs
  useEffect(() => {
    if (generationLogs.length === 0) return;

    // Recalculer les étapes terminées à chaque fois
    const newCompletedSteps = [];

    // Vérifier les erreurs de limitation de débit et de disponibilité du modèle
    const hasError = generationLogs.some(
      (log) =>
        log.includes("RATE_LIMIT_EXCEEDED") ||
        log.includes("heavy load") ||
        log.includes("rate limit") ||
        log.includes("Required models not available") ||
        log.includes("Configuration failed") ||
        log.includes("Error") ||
        log.includes("ERROR")
    );

    if (hasError) {
      // Vérifier d'abord le cas spécifique du document avec info insuffisante
      const insufficientInfoMessage = generationLogs.find((log) =>
        log.includes(
          "Failed to generate benchmark: The document does not contain enough information"
        )
      );

      if (insufficientInfoMessage) {
        setError(
          "Your document doesn't contain enough information to generate a benchmark. Please try with a more comprehensive document that includes richer content."
        );
        notifyGenerationComplete(
          false,
          null,
          "Insufficient document information"
        );
        return;
      }

      const errorMessage =
        generationLogs.find(
          (log) =>
            log.includes("Required models not available") ||
            log.includes("Configuration failed") ||
            log.includes("Error generating configuration")
        ) ||
        "The demo is under heavy load at the moment. Please try again later.";

      setError(errorMessage);
      notifyGenerationComplete(false, null, errorMessage);
      return;
    }

    // Identifier toutes les étapes terminées dans tous les logs
    generationLogs.forEach((log) => {
      const match = log.match(/\[SUCCESS\] Stage completed: (\w+)/);
      if (match && match[1]) {
        const completedStep = match[1].trim();
        if (
          BENCHMARK_STEPS.includes(completedStep) &&
          !newCompletedSteps.includes(completedStep)
        ) {
          newCompletedSteps.push(completedStep);
        }
      }
    });

    // Déterminer l'étape active en fonction des étapes terminées
    let newActiveStep = activeStep;

    if (newCompletedSteps.length > 0) {
      // Trouver l'étape la plus avancée dans les logs
      const maxCompletedStepIndex = Math.max(
        ...newCompletedSteps.map((step) => BENCHMARK_STEPS.indexOf(step))
      );
      // Passer à l'étape suivante
      const calculatedStep = maxCompletedStepIndex + 1;

      // Mettre à jour uniquement si la nouvelle étape est plus avancée que l'étape actuelle
      if (calculatedStep > activeStep) {
        newActiveStep = calculatedStep;
      }

      // S'assurer que activeStep ne dépasse pas le nombre total d'étapes
      if (newActiveStep >= BENCHMARK_STEPS.length) {
        newActiveStep = BENCHMARK_STEPS.length;
      }
    } else if (activeStep === 0) {
      // Si aucune étape n'est trouvée et que l'étape active est 0, passer à 1
      newActiveStep = 1;
    }

    // Mettre à jour l'état si les étapes ont changé
    if (JSON.stringify(newCompletedSteps) !== JSON.stringify(completedSteps)) {
      setCompletedSteps(newCompletedSteps);
    }

    // Mettre à jour l'étape active uniquement si elle a changé
    if (newActiveStep !== activeStep) {
      setActiveStep(newActiveStep);
    }

    // Ignorer le reste du traitement des logs si nous simulons
    if (isDefault) return;

    // Vérifier les derniers logs pour déterminer la phase actuelle
    const recentLogs = generationLogs.slice(-10);

    // Détecter les conditions d'achèvement
    const isComplete =
      recentLogs.some((log) =>
        log.includes("[SUCCESS] Benchmark process completed successfully")
      ) ||
      recentLogs.some((log) =>
        log.includes("[SUCCESS] Ingestion process completed successfully")
      ) ||
      newCompletedSteps.includes("single_shot_question_generation") ||
      newActiveStep >= BENCHMARK_STEPS.length;

    if (isComplete) {
      setCurrentPhase("complete");
      notifyGenerationComplete(true, generationLogs);
    } else if (
      recentLogs.some((log) => log.includes("Starting ingestion process"))
    ) {
      setCurrentPhase("benchmarking");
    } else if (
      recentLogs.some((log) => log.includes("Generating base configuration"))
    ) {
      setCurrentPhase("configuring");
    }
  }, [
    generationLogs,
    completedSteps,
    activeStep,
    sessionId,
    onComplete,
    isDefault,
  ]);

  // Générer le benchmark
  const generateBenchmark = async () => {
    if (!sessionId) {
      setError("Missing session ID");
      return;
    }

    resetGenerationStates();

    try {
      // Appeler l'API pour générer le benchmark
      const response = await fetch(
        `${API_CONFIG.BASE_URL}/generate-benchmark`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ session_id: sessionId }),
        }
      );

      const result = await response.json();

      if (response.ok) {
        setGenerationLogs(result.logs || []);

        // Configurer le polling pour suivre la progression
        pollingIntervalRef.current = setInterval(async () => {
          // Vérifier si nous avons déjà terminé
          if (generationComplete) {
            clearInterval(pollingIntervalRef.current);
            return;
          }

          try {
            // Appeler l'API pour obtenir les derniers logs
            const logsResponse = await fetch(
              `${API_CONFIG.BASE_URL}/benchmark-progress/${sessionId}`
            );

            if (logsResponse.ok) {
              const logsResult = await logsResponse.json();

              // Mettre à jour les logs s'il y en a de nouveaux
              if (
                logsResult.logs &&
                logsResult.logs.length > generationLogs.length
              ) {
                setGenerationLogs(logsResult.logs);
              }

              // Vérifier si la tâche est terminée
              if (logsResult.is_completed) {
                setGenerationComplete(true);
                clearInterval(pollingIntervalRef.current);
              }
            }
          } catch (error) {
            console.log("Error polling for logs:", error);
            // Ne pas arrêter le polling en cas d'erreurs réseau
          }
        }, 2000); // Sondage toutes les 2 secondes
      } else {
        // Gérer l'erreur
        setGenerationLogs([`Error: ${result.error || "Unknown error"}`]);
        setError(result.error || "Benchmark generation failed");
      }
    } catch (error) {
      console.error("Error generating benchmark:", error);
      setGenerationLogs([`Error: ${error.message || "Unknown error"}`]);
      setError("Server connection error");
    } finally {
      setGenerating(false);
    }
  };

  // Obtenir les informations sur l'étape actuelle pour l'affichage
  const getCurrentStepInfo = () => {
    const totalSteps = BENCHMARK_STEPS.length;
    const currentStepIndex = activeStep;

    // S'il n'y a pas encore d'étape active
    if (currentStepIndex <= 1 && completedSteps.length === 0) {
      return `Starting (1/${totalSteps})`;
    }

    // Si toutes les étapes sont terminées
    if (currentStepIndex >= totalSteps) {
      return `Complete (${totalSteps}/${totalSteps})`;
    }

    // Obtenir le nom de l'étape actuelle
    const currentStepName =
      STEP_LABELS[BENCHMARK_STEPS[currentStepIndex]] || "Processing";

    return `${currentStepName} (${currentStepIndex}/${totalSteps})`;
  };

  // Formater le temps écoulé en HH:MM:SS
  const formatElapsedTime = () => {
    const hours = Math.floor(elapsedTime / 3600);
    const minutes = Math.floor((elapsedTime % 3600) / 60);
    const seconds = elapsedTime % 60;

    return [
      hours.toString().padStart(2, "0"),
      minutes.toString().padStart(2, "0"),
      seconds.toString().padStart(2, "0"),
    ].join(":");
  };

  // Si terminé, arrêter le timer
  useEffect(() => {
    if (generationComplete && timerIntervalRef.current) {
      clearInterval(timerIntervalRef.current);
    }
  }, [generationComplete]);

  const handleGenerationComplete = (result) => {
    console.log("Benchmark generation completed:", result);
    if (result && result.success && !hasRedirectedRef.current) {
      hasRedirectedRef.current = true; // Marquer que la redirection a été faite
      // Légère pause avant de naviguer pour éviter les problèmes de synchronisation
      setTimeout(() => {
        navigate(`/benchmark-display?session=${sessionId}`);
      }, 500);
    } else if (result && !result.success) {
      // Afficher l'erreur au lieu de rediriger
      setError(result.error || "An error occurred during benchmark generation");
    }
  };

  return (
    <Paper
      elevation={3}
      sx={{
        p: 4,
        mt: 3,
        mb: 3,
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
        minHeight: 200,
        position: "relative",
      }}
    >
      {/* Estimated time */}
      <Box
        sx={{
          position: "absolute",
          top: 12,
          right: 12,
          backgroundColor: "rgba(0, 0, 0, 0.04)",
          borderRadius: "4px",
          px: 1,
          py: 0.5,
          display: "inline-flex",
          alignItems: "center",
        }}
      >
        <Typography
          variant="caption"
          sx={{
            fontSize: "0.675rem",
            color: "text.secondary",
            fontWeight: 500,
          }}
        >
          Estimated time ~ 1m30s
        </Typography>
      </Box>

      {error ? (
        <ErrorDisplay error={error} />
      ) : (
        <>
          <CircularProgress size={60} sx={{ mb: 2 }} />
          <Typography variant="h6" component="div" gutterBottom>
            Creating benchmark...
          </Typography>

          {/* Step progress indicator */}
          <Typography variant="body1" color="text.secondary">
            {getCurrentStepInfo()}
          </Typography>

          {/* Timer display */}
          <Box
            sx={{
              display: "flex",
              alignItems: "center",
              mt: 1,
              color: "text.secondary",
            }}
          >
            <Typography variant="body2" sx={{ opacity: 0.5 }}>
              {formatElapsedTime()}
            </Typography>
          </Box>
        </>
      )}

      {/* Use the LogDisplay component */}
      {/* <LogDisplay logs={generationLogs} height={150} /> */}
    </Paper>
  );
};

export default Generator;
