import { answerEvaluation, } from '../../../api/knowledge/post-answer-evaluation.js';
import { answerApi, fetchAnswer, selectAnswer, } from '../../../api/knowledge/stream-answer-api.js';
import { warnIfUsingNextAnalyticsModeForServiceFeature } from '../../../app/engine.js';
import { selectAnswerApiQueryParams, selectAnswerTriggerParams, } from '../../../features/generated-answer/answer-api-selectors.js';
import { generateAnswer, resetAnswer, sendGeneratedAnswerFeedback, updateAnswerConfigurationId, } from '../../../features/generated-answer/generated-answer-actions.js';
import { filterOutDuplicatedCitations } from '../../../features/generated-answer/utils/generated-answer-citation-utils.js';
import { queryReducer as query } from '../../../features/query/query-slice.js';
import { loadReducerError } from '../../../utils/errors.js';
import { buildCoreGeneratedAnswer, } from '../../core/generated-answer/headless-core-generated-answer.js';
const parseEvaluationDetails = (detail) => {
    if (detail === 'yes') {
        return true;
    }
    if (detail === 'no') {
        return false;
    }
    return null;
};
const parseEvaluationArguments = ({ answerApiState, feedback, query, }) => ({
    additionalNotes: feedback.details ?? null,
    answer: {
        text: answerApiState.answer,
        responseId: answerApiState.answerId,
        format: answerApiState.contentFormat ?? 'text/plain',
    },
    correctAnswerUrl: feedback.documentUrl ?? null,
    details: {
        correctTopic: parseEvaluationDetails(feedback.correctTopic),
        documented: parseEvaluationDetails(feedback.documented),
        hallucinationFree: parseEvaluationDetails(feedback.hallucinationFree),
        readable: parseEvaluationDetails(feedback.readable),
    },
    helpful: feedback.helpful,
    question: query,
});
const subscribeToSearchRequest = (engine) => {
    let lastRequestId = '';
    const strictListener = () => {
        const state = engine.state;
        const triggerParams = selectAnswerTriggerParams(state);
        const currentRequestId = triggerParams.requestId;
        const newSearchRequestDetected = currentRequestId !== lastRequestId;
        if (newSearchRequestDetected) {
            lastRequestId = currentRequestId;
            engine.dispatch(resetAnswer());
            if (triggerParams.q?.length > 0) {
                engine.dispatch(generateAnswer());
            }
        }
    };
    engine.subscribe(strictListener);
};
/**
 *
 * @internal
 *
 * Creates a `AnswerApiGeneratedAnswer` controller instance using the Answer API stream pattern.
 *
 * @param engine - The headless engine.
 * @param props - The configurable `AnswerApiGeneratedAnswer` properties.
 * @returns A `AnswerApiGeneratedAnswer` controller instance.
 */
export function buildAnswerApiGeneratedAnswer(engine, analyticsClient, props = {}) {
    if (!loadAnswerApiReducers(engine)) {
        throw loadReducerError;
    }
    warnIfUsingNextAnalyticsModeForServiceFeature(engine.state.configuration.analytics.analyticsMode);
    const { ...controller } = buildCoreGeneratedAnswer(engine, analyticsClient, props);
    const getState = () => engine.state;
    engine.dispatch(updateAnswerConfigurationId(props.answerConfigurationId));
    subscribeToSearchRequest(engine);
    return {
        ...controller,
        get state() {
            const answerApiState = selectAnswer(engine.state).data;
            const state = getState().generatedAnswer;
            return {
                ...state,
                answer: answerApiState?.answer,
                citations: filterOutDuplicatedCitations(answerApiState?.citations ?? []),
                error: {
                    message: answerApiState?.error?.message,
                    statusCode: answerApiState?.error?.code,
                },
                isLoading: answerApiState?.isLoading ?? false,
                isStreaming: answerApiState?.isStreaming ?? false,
                answerContentFormat: answerApiState?.contentFormat ?? 'text/plain',
                isAnswerGenerated: answerApiState?.generated ?? false,
                cannotAnswer: state.cannotAnswer ||
                    (answerApiState?.generated === false &&
                        !answerApiState?.isLoading &&
                        !answerApiState?.isStreaming),
            };
        },
        retry() {
            const answerApiQueryParams = selectAnswerApiQueryParams(getState());
            engine.dispatch(fetchAnswer(answerApiQueryParams));
        },
        reset() {
            engine.dispatch(resetAnswer());
        },
        async sendFeedback(feedback) {
            engine.dispatch(analyticsClient.logGeneratedAnswerFeedback(feedback));
            const args = parseEvaluationArguments({
                query: getState().query.q,
                feedback,
                answerApiState: selectAnswer(engine.state).data,
            });
            engine.dispatch(answerEvaluation.endpoints.post.initiate(args));
            engine.dispatch(sendGeneratedAnswerFeedback());
        },
    };
}
function loadAnswerApiReducers(engine) {
    engine.addReducers({ [answerApi.reducerPath]: answerApi.reducer, query });
    return true;
}
