import { useCallback, useEffect, useState, useRef } from "react";
import { getCombinedIndexStatus, cleanupBatches, populateCentroids, processCompletedBatches, getProviderInfo, rebuildIndex, generateEmbeddings, getQueueStatus, getStagingStats, retryFailedEmbeddingRequests, stopEmbeddingGeneration, cancelCollection, } from "../../services/indexService";
import { useEditContext } from "../../client/editContext";
/**
 * Custom hook that manages all state and actions for the IndexOverview component
 */
export function useIndexStatus() {
    const [indexStatus, setIndexStatus] = useState(null);
    const [isLoading, setIsLoading] = useState(false);
    const [isCleaning, setIsCleaning] = useState(false);
    const [isPopulating, setIsPopulating] = useState(false);
    const [kCentroids, setKCentroids] = useState(1024);
    const [error, setError] = useState(null);
    const [isFinalizing, setIsFinalizing] = useState(false);
    const [stageResult, setStageResult] = useState(null);
    const [importStatus, setImportStatus] = useState(null);
    const [centroidsStatus, setCentroidsStatus] = useState(null);
    const [collectionStatus, setCollectionStatus] = useState(null);
    const [isCollecting, setIsCollecting] = useState(false);
    const [isGenerating, setIsGenerating] = useState(false);
    const [showAdvanced, setShowAdvanced] = useState(false);
    const [providerInfo, setProviderInfo] = useState(null);
    const [queueStatus, setQueueStatus] = useState(null);
    const [showQueueErrors, setShowQueueErrors] = useState(false);
    const [forceRegenerate, setForceRegenerate] = useState(false);
    const [stagingStats, setStagingStats] = useState(null);
    const [isRetryingFailed, setIsRetryingFailed] = useState(false);
    const [retryFailedMessage, setRetryFailedMessage] = useState(null);
    const [isCancellingCollection, setIsCancellingCollection] = useState(false);
    const [debouncedCurrentItem, setDebouncedCurrentItem] = useState(undefined);
    const currentItemDebounceTimerRef = useRef(null);
    const editContext = useEditContext();
    // Fetch functions
    const fetchProviderInfo = async () => {
        try {
            const info = await getProviderInfo();
            setProviderInfo(info);
        }
        catch (err) {
            console.error("Failed to fetch provider info:", err);
        }
    };
    const fetchStagingStats = async () => {
        try {
            const stats = await getStagingStats();
            setStagingStats(stats);
        }
        catch (err) {
            console.error("Failed to fetch staging stats:", err);
        }
    };
    const fetchStatus = async () => {
        try {
            setIsLoading(true);
            setError(null);
            const combined = await getCombinedIndexStatus();
            setIndexStatus(combined?.indexStatus || null);
            setImportStatus(combined?.importStatus || null);
            setCentroidsStatus(combined?.centroidsStatus || null);
            setCollectionStatus(combined?.collectionStatus || null);
            setQueueStatus(combined?.queueStatus || null);
            // Also fetch staging stats for state recovery
            await fetchStagingStats();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to fetch index status");
        }
        finally {
            setIsLoading(false);
        }
    };
    const fetchQueueStatus = async () => {
        try {
            const status = await getQueueStatus();
            setQueueStatus(status);
        }
        catch (err) {
            console.error("Failed to fetch queue status:", err);
        }
    };
    // Handler functions
    const handleRetryFailed = async () => {
        try {
            setIsRetryingFailed(true);
            setError(null);
            setRetryFailedMessage(null);
            const result = await retryFailedEmbeddingRequests();
            setRetryFailedMessage(result.retried > 0
                ? `Retried ${result.retried.toLocaleString()} failed request${result.retried === 1 ? "" : "s"}.`
                : "No failed requests found to retry.");
            await fetchQueueStatus();
            await fetchStagingStats();
            await fetchStatus();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to retry failed requests");
        }
        finally {
            setIsRetryingFailed(false);
        }
    };
    const handleStopGeneration = async () => {
        try {
            setIsLoading(true);
            setError(null);
            await stopEmbeddingGeneration();
            await fetchQueueStatus();
            await fetchStagingStats();
            await fetchStatus();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to stop generation");
        }
        finally {
            setIsLoading(false);
        }
    };
    const handleCancelCollection = async () => {
        try {
            setIsCancellingCollection(true);
            setError(null);
            await cancelCollection();
            await fetchStagingStats();
            await fetchStatus();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to cancel collection");
        }
        finally {
            setIsCancellingCollection(false);
        }
    };
    const handleRebuild = async () => {
        try {
            setIsCollecting(true);
            setError(null);
            const result = await rebuildIndex(forceRegenerate);
            setStageResult(result);
            await fetchStatus();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to start rebuild");
        }
        finally {
            setIsCollecting(false);
        }
    };
    const handleGenerateEmbeddings = async (mode) => {
        try {
            setIsGenerating(true);
            setError(null);
            await generateEmbeddings(mode);
            setStageResult(null); // Clear stage result after starting generation
            await fetchStatus();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to generate embeddings");
        }
        finally {
            setIsGenerating(false);
        }
    };
    const handleCleanup = async () => {
        try {
            setIsCleaning(true);
            setError(null);
            await cleanupBatches();
            await fetchStatus();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to cleanup batches");
        }
        finally {
            setIsCleaning(false);
        }
    };
    const handlePopulateCentroids = async () => {
        try {
            setIsPopulating(true);
            setError(null);
            await populateCentroids(kCentroids || 1024);
            await fetchStatus();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to populate centroids");
        }
        finally {
            setIsPopulating(false);
        }
    };
    const handleFinalize = async () => {
        try {
            setIsFinalizing(true);
            setError(null);
            await processCompletedBatches();
            await fetchStatus();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to finalize rebuild");
        }
        finally {
            setIsFinalizing(false);
        }
    };
    const goToSettings = useCallback(() => {
        // Ensure URL reflects the target view and panel before switching views
        editContext?.updateUrl({ view: "settings", ccpanel: "search-config" });
        editContext?.switchWorkspace("settings");
    }, [editContext]);
    const clearStaging = () => {
        setStageResult(null);
        setStagingStats(null);
    };
    // Unified flag so we can show some UI (like error summaries) only when the whole rebuild is finished.
    const operationInProgress = (() => {
        const batches = indexStatus?.batches || [];
        const inProgressCount = batches.filter((b) => {
            const s = (b.status || "").toLowerCase();
            return s === "submitted" || s === "processing" || s === "queued";
        }).length;
        return !!(isCollecting ||
            collectionStatus?.isCollecting ||
            isGenerating ||
            (queueStatus?.isRunning && (queueStatus?.pendingCount ?? 0) > 0) ||
            inProgressCount > 0 ||
            indexStatus?.rebuilding ||
            importStatus?.isImporting ||
            centroidsStatus?.isPopulating);
    })();
    // Fetch initial status on mount and on WebSocket reconnection
    useEffect(() => {
        fetchStatus();
        fetchProviderInfo();
    }, [editContext?.socketConnectionVersion]);
    // Subscribe to websocket rebuild status updates
    useEffect(() => {
        if (!editContext?.addSocketMessageListener)
            return;
        const unsubscribe = editContext.addSocketMessageListener((message) => {
            if (message.type === "index-rebuild-status") {
                const payload = message.payload;
                if (!payload)
                    return;
                const phase = payload.phase;
                const subPhase = payload.subPhase;
                const isActive = payload.isActive;
                const status = payload.status ?? "";
                const itemsProcessed = payload.itemsProcessed;
                const languageVersionsProcessed = payload.languageVersionsProcessed;
                const batchesUploaded = payload.batchesUploaded;
                const successCount = payload.successCount;
                const errorCount = payload.errorCount;
                const recentErrors = payload.recentErrors;
                const currentItem = payload.currentItem;
                const currentBatch = payload.currentBatch;
                const pendingCount = payload.pendingCount;
                if (phase === "collection") {
                    // Debounce currentItem updates to prevent flickering
                    if (currentItem !== undefined) {
                        if (currentItemDebounceTimerRef.current) {
                            clearTimeout(currentItemDebounceTimerRef.current);
                        }
                        currentItemDebounceTimerRef.current = setTimeout(() => {
                            setDebouncedCurrentItem(currentItem);
                        }, 300); // Update every 300ms instead of on every message
                    }
                    setCollectionStatus((prev) => {
                        // Only update if important fields changed (not just currentItem)
                        // This prevents flickering when only currentItem updates
                        const statusChanged = status && status !== prev?.status;
                        const subPhaseChanged = subPhase && subPhase !== prev?.subPhase;
                        const itemsChanged = itemsProcessed !== undefined &&
                            itemsProcessed !== prev?.itemsProcessed;
                        const versionsChanged = languageVersionsProcessed !== undefined &&
                            languageVersionsProcessed !== prev?.languageVersionsProcessed;
                        const batchesChanged = batchesUploaded !== undefined &&
                            batchesUploaded !== prev?.batchesUploaded;
                        const batchChanged = currentBatch !== undefined && currentBatch !== prev?.currentBatch;
                        const activeChanged = isActive !== prev?.isCollecting;
                        // If only currentItem changed (and nothing else), skip the update
                        // currentItem is handled separately via debounced state
                        if (!statusChanged &&
                            !subPhaseChanged &&
                            !itemsChanged &&
                            !versionsChanged &&
                            !batchesChanged &&
                            !batchChanged &&
                            !activeChanged) {
                            return prev;
                        }
                        return {
                            isCollecting: isActive === true,
                            status: status || prev?.status || "",
                            startedAt: isActive ? new Date().toISOString() : prev?.startedAt,
                            itemsProcessed: itemsProcessed !== undefined
                                ? itemsProcessed
                                : (prev?.itemsProcessed ?? 0),
                            languageVersionsProcessed: languageVersionsProcessed !== undefined
                                ? languageVersionsProcessed
                                : (prev?.languageVersionsProcessed ?? 0),
                            batchesUploaded: batchesUploaded !== undefined
                                ? batchesUploaded
                                : (prev?.batchesUploaded ?? 0),
                            subPhase: subPhase ?? prev?.subPhase,
                            currentItem: currentItem, // Keep for reference but display uses debounced version
                            currentBatch: currentBatch !== undefined ? currentBatch : prev?.currentBatch,
                            // recentWarnings aren't streamed via websocket; preserve the value
                            // fetched from /CombinedStatus. The next poll refresh will update it.
                            recentWarnings: prev?.recentWarnings,
                        };
                    });
                    // Update queue pending count if provided
                    if (pendingCount !== undefined) {
                        setQueueStatus((prev) => ({
                            isRunning: prev?.isRunning ?? false,
                            status: prev?.status ?? "",
                            processedCount: prev?.processedCount ?? 0,
                            errorCount: prev?.errorCount ?? 0,
                            pendingCount: pendingCount,
                            recentErrors: prev?.recentErrors ?? [],
                        }));
                    }
                    // Refresh full status when collection completes to get batch info
                    if (!isActive) {
                        // Clear debounce timer when collection completes
                        if (currentItemDebounceTimerRef.current) {
                            clearTimeout(currentItemDebounceTimerRef.current);
                            currentItemDebounceTimerRef.current = null;
                        }
                        setDebouncedCurrentItem(undefined);
                        fetchStatus();
                    }
                }
                // Update import/generation status
                if (phase === "import" || phase === "generation") {
                    setImportStatus((prev) => ({
                        isImporting: isActive === true,
                        status: status,
                        startedAt: isActive ? new Date().toISOString() : prev?.startedAt,
                        successCount: successCount ?? 0,
                        errorCount: errorCount ?? 0,
                        recentErrors: recentErrors || [],
                    }));
                    // Refresh full status when import completes to get updated index count
                    if (!isActive) {
                        fetchStatus();
                    }
                }
                // Update centroids status
                if (phase === "centroids") {
                    setCentroidsStatus((prev) => ({
                        isPopulating: isActive === true,
                        status: status,
                        startedAt: isActive ? new Date().toISOString() : prev?.startedAt,
                    }));
                    // Refresh full status when centroids population completes
                    if (!isActive) {
                        fetchStatus();
                    }
                }
            }
            // Handle queue status updates
            if (message.type === "embedding-queue-status") {
                const payload = message.payload;
                if (!payload)
                    return;
                const isActive = payload.isActive ?? false;
                const status = payload.status ?? "";
                const processedCount = payload.processedCount ?? 0;
                const errorCount = payload.errorCount ?? 0;
                const pendingCount = payload.pendingCount ?? 0;
                const recentErrors = payload.recentErrors ?? [];
                setQueueStatus({
                    isRunning: isActive,
                    status: status,
                    processedCount: processedCount,
                    errorCount: errorCount,
                    pendingCount: pendingCount,
                    recentErrors: recentErrors,
                });
                if (!isActive) {
                    setImportStatus((prev) => prev?.isImporting
                        ? {
                            ...prev,
                            isImporting: false,
                            status: status || prev.status,
                            errorCount,
                            recentErrors,
                        }
                        : prev);
                    fetchStatus();
                }
            }
        });
        return unsubscribe;
    }, [editContext]);
    // Cleanup debounce timer on unmount or when collection stops
    useEffect(() => {
        return () => {
            if (currentItemDebounceTimerRef.current) {
                clearTimeout(currentItemDebounceTimerRef.current);
            }
        };
    }, []);
    // Clear debounced currentItem when collection stops
    useEffect(() => {
        if (!collectionStatus?.isCollecting && !isCollecting) {
            setDebouncedCurrentItem(undefined);
            if (currentItemDebounceTimerRef.current) {
                clearTimeout(currentItemDebounceTimerRef.current);
                currentItemDebounceTimerRef.current = null;
            }
        }
    }, [collectionStatus?.isCollecting, isCollecting]);
    const state = {
        indexStatus,
        isLoading,
        isCleaning,
        isPopulating,
        kCentroids,
        error,
        isFinalizing,
        stageResult,
        importStatus,
        centroidsStatus,
        collectionStatus,
        isCollecting,
        isGenerating,
        showAdvanced,
        providerInfo,
        queueStatus,
        showQueueErrors,
        forceRegenerate,
        stagingStats,
        isRetryingFailed,
        retryFailedMessage,
        isCancellingCollection,
        debouncedCurrentItem,
        operationInProgress,
    };
    const actions = {
        fetchStatus,
        fetchProviderInfo,
        handleRetryFailed,
        handleStopGeneration,
        handleCancelCollection,
        handleRebuild,
        handleGenerateEmbeddings,
        handleCleanup,
        handlePopulateCentroids,
        handleFinalize,
        goToSettings,
        setShowQueueErrors,
        setShowAdvanced,
        setKCentroids,
        setForceRegenerate,
        clearStaging,
    };
    return { state, actions };
}
//# sourceMappingURL=useIndexStatus.js.map