/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { useEffect, useReducer, useRef } from 'react';
import { FileSearchFactory, escapePath } from 'sixth-cli-core';
import { MAX_SUGGESTIONS_TO_SHOW } from '../components/SuggestionsDisplay.js';
export var AtCompletionStatus;
(function (AtCompletionStatus) {
    AtCompletionStatus["IDLE"] = "idle";
    AtCompletionStatus["INITIALIZING"] = "initializing";
    AtCompletionStatus["READY"] = "ready";
    AtCompletionStatus["SEARCHING"] = "searching";
    AtCompletionStatus["ERROR"] = "error";
})(AtCompletionStatus || (AtCompletionStatus = {}));
const initialState = {
    status: AtCompletionStatus.IDLE,
    suggestions: [],
    isLoading: false,
    pattern: null,
};
function atCompletionReducer(state, action) {
    switch (action.type) {
        case 'INITIALIZE':
            return {
                ...state,
                status: AtCompletionStatus.INITIALIZING,
                isLoading: true,
            };
        case 'INITIALIZE_SUCCESS':
            return { ...state, status: AtCompletionStatus.READY, isLoading: false };
        case 'SEARCH':
            // Keep old suggestions, don't set loading immediately
            return {
                ...state,
                status: AtCompletionStatus.SEARCHING,
                pattern: action.payload,
            };
        case 'SEARCH_SUCCESS':
            return {
                ...state,
                status: AtCompletionStatus.READY,
                suggestions: action.payload,
                isLoading: false,
            };
        case 'SET_LOADING':
            // Only show loading if we are still in a searching state
            if (state.status === AtCompletionStatus.SEARCHING) {
                return { ...state, isLoading: action.payload, suggestions: [] };
            }
            return state;
        case 'ERROR':
            return {
                ...state,
                status: AtCompletionStatus.ERROR,
                isLoading: false,
                suggestions: [],
            };
        case 'RESET':
            return initialState;
        default:
            return state;
    }
}
export function useAtCompletion(props) {
    const { enabled, pattern, config, cwd, setSuggestions, setIsLoadingSuggestions, } = props;
    const [state, dispatch] = useReducer(atCompletionReducer, initialState);
    const fileSearch = useRef(null);
    const searchAbortController = useRef(null);
    const slowSearchTimer = useRef(null);
    useEffect(() => {
        setSuggestions(state.suggestions);
    }, [state.suggestions, setSuggestions]);
    useEffect(() => {
        setIsLoadingSuggestions(state.isLoading);
    }, [state.isLoading, setIsLoadingSuggestions]);
    useEffect(() => {
        dispatch({ type: 'RESET' });
    }, [cwd, config]);
    // Reacts to user input (`pattern`) ONLY.
    useEffect(() => {
        if (!enabled) {
            // reset when first getting out of completion suggestions
            if (state.status === AtCompletionStatus.READY ||
                state.status === AtCompletionStatus.ERROR) {
                dispatch({ type: 'RESET' });
            }
            return;
        }
        if (pattern === null) {
            dispatch({ type: 'RESET' });
            return;
        }
        if (state.status === AtCompletionStatus.IDLE) {
            dispatch({ type: 'INITIALIZE' });
        }
        else if ((state.status === AtCompletionStatus.READY ||
            state.status === AtCompletionStatus.SEARCHING) &&
            pattern.toLowerCase() !== state.pattern // Only search if the pattern has changed
        ) {
            dispatch({ type: 'SEARCH', payload: pattern.toLowerCase() });
        }
    }, [enabled, pattern, state.status, state.pattern]);
    // The "Worker" that performs async operations based on status.
    useEffect(() => {
        const initialize = async () => {
            try {
                const searcher = FileSearchFactory.create({
                    projectRoot: cwd,
                    ignoreDirs: [],
                    useGitignore: config?.getFileFilteringOptions()?.respectGitIgnore ?? true,
                    useGeminiignore: config?.getFileFilteringOptions()?.respectGeminiIgnore ?? true,
                    cache: true,
                    cacheTtl: 30, // 30 seconds
                    enableRecursiveFileSearch: config?.getEnableRecursiveFileSearch() ?? true,
                    disableFuzzySearch: config?.getFileFilteringDisableFuzzySearch() ?? false,
                });
                await searcher.initialize();
                fileSearch.current = searcher;
                dispatch({ type: 'INITIALIZE_SUCCESS' });
                if (state.pattern !== null) {
                    dispatch({ type: 'SEARCH', payload: state.pattern });
                }
            }
            catch (_) {
                dispatch({ type: 'ERROR' });
            }
        };
        const search = async () => {
            if (!fileSearch.current || state.pattern === null) {
                return;
            }
            if (slowSearchTimer.current) {
                clearTimeout(slowSearchTimer.current);
            }
            const controller = new AbortController();
            searchAbortController.current = controller;
            slowSearchTimer.current = setTimeout(() => {
                dispatch({ type: 'SET_LOADING', payload: true });
            }, 200);
            try {
                const results = await fileSearch.current.search(state.pattern, {
                    signal: controller.signal,
                    maxResults: MAX_SUGGESTIONS_TO_SHOW * 3,
                });
                if (slowSearchTimer.current) {
                    clearTimeout(slowSearchTimer.current);
                }
                if (controller.signal.aborted) {
                    return;
                }
                const suggestions = results.map((p) => ({
                    label: p,
                    value: escapePath(p),
                }));
                dispatch({ type: 'SEARCH_SUCCESS', payload: suggestions });
            }
            catch (error) {
                if (!(error instanceof Error && error.name === 'AbortError')) {
                    dispatch({ type: 'ERROR' });
                }
            }
        };
        if (state.status === AtCompletionStatus.INITIALIZING) {
            initialize();
        }
        else if (state.status === AtCompletionStatus.SEARCHING) {
            search();
        }
        return () => {
            searchAbortController.current?.abort();
            if (slowSearchTimer.current) {
                clearTimeout(slowSearchTimer.current);
            }
        };
    }, [state.status, state.pattern, config, cwd]);
}
//# sourceMappingURL=useAtCompletion.js.map