import React, {
    createContext,
    useContext,
    useReducer,
    ReactNode,
    useEffect,
    useRef,
} from 'react';
import { quizReducer, initialState } from './QuizReducer';
import { getQuizSession } from '../services/api';
import { setQuizToken } from '@/lib/quizApiClient';
import type {
    QuizAction,
    QuizState,
    QuizScreen,
    QuizSessionState,
    QuizGuest,
    CampaignStatus,
    QuizSession,
    CurrentQuestion,
    AnswerFeedback,
    QuizOptionKey,
} from './QuizActions';

interface QuizContextValue {
    state: QuizState;
    dispatch: React.Dispatch<QuizAction>;
}

const QuizContext = createContext<QuizContextValue | undefined>(undefined);

export function QuizProvider({ children }: { children: ReactNode }) {
    const [state, dispatch] = useReducer(quizReducer, initialState);
    const hydratedTokenRef = useRef<string | null>(null);

    // Hydrate token from localStorage on mount
    useEffect(() => {
        const token = localStorage.getItem('quiz_token');
        if (token) {
            dispatch({ type: 'SET_TOKEN', payload: token });
        }
    }, []);

    // Hydrate guest from localStorage on mount
    useEffect(() => {
        const guestStr = localStorage.getItem('quiz_guest');
        if (guestStr) {
            try {
                const guest = JSON.parse(guestStr);
                dispatch({ type: 'SET_GUEST', payload: guest });
            } catch (e) {
                console.error('Failed to parse guest from localStorage');
            }
        }
    }, []);

    // Hydrate the API client and persisted token together. The client keeps an
    // in-memory token, so localStorage alone is not sufficient after OTP.
    useEffect(() => {
        setQuizToken(state.token);
    }, [state.token]);

    // Recover server state once per persisted token, including the valid
    // "new" state whose session is intentionally null.
    useEffect(() => {
        if (state.token && hydratedTokenRef.current !== state.token) {
            hydratedTokenRef.current = state.token;
            getQuizSession()
                .then((response) => {
                    dispatch({
                        type: 'SET_SESSION_STATE',
                        payload: response.data.state,
                    });
                    dispatch({
                        type: 'SET_SESSION',
                        payload: response.data.session,
                    });
                    if (response.data.guest) {
                        dispatch({
                            type: 'SET_GUEST',
                            payload: response.data.guest,
                        });
                    }
                })
                .catch(() => {
                    // If session fetch fails, clear invalid token
                    dispatch({ type: 'SET_TOKEN', payload: null });
                    localStorage.removeItem('quiz_token');
                });
        }
        if (!state.token) hydratedTokenRef.current = null;
    }, [state.token]);

    // Persist token to localStorage when it changes
    useEffect(() => {
        if (state.token) {
            localStorage.setItem('quiz_token', state.token);
        } else {
            localStorage.removeItem('quiz_token');
        }
    }, [state.token]);

    // Persist guest to localStorage when it changes
    useEffect(() => {
        if (state.guest) {
            localStorage.setItem('quiz_guest', JSON.stringify(state.guest));
        } else {
            localStorage.removeItem('quiz_guest');
        }
    }, [state.guest]);

    return (
        <QuizContext.Provider value={{ state, dispatch }}>
            {children}
        </QuizContext.Provider>
    );
}

export function useQuizContext() {
    const context = useContext(QuizContext);
    if (!context) {
        throw new Error('useQuizContext must be used within a QuizProvider');
    }
    return context;
}

export type {
    QuizState,
    QuizScreen,
    QuizSessionState,
    QuizGuest,
    CampaignStatus,
    QuizSession,
    CurrentQuestion,
    AnswerFeedback,
    QuizOptionKey,
    QuizAction,
};
