import React, {
    createContext,
    useCallback,
    useContext,
    useEffect,
    useReducer,
} from 'react';
import type { Label } from 'src/types';

const LOCAL_STORAGE_SELECTED_LABEL = 'publishing_selected_label_uuid';

const enum LabelActionType {
    setLabel = 'setLabel',
}

interface LabelAction {
    type: LabelActionType;
    payload: Label | null;
}

export interface LabelState {
    label: Label | null;
}

interface LabelContextType {
    label: Label | null;
    setLabel: (value: Label | null) => void;
}

export const initialLabelState: LabelState = {
    label: null,
};

const LabelContext = createContext<LabelContextType>({
    label: initialLabelState.label,
    setLabel: () => null,
});

const labelReducer = (state: LabelState, action: LabelAction): LabelState => {
    switch (action.type) {
        case LabelActionType.setLabel: {
            return {
                ...state,
                label: action.payload,
            };
        }

        default:
            return state;
    }
};

interface LabelContextProviderProps {
    children: React.ReactNode;
}

export const LabelContextProvider: React.FC<LabelContextProviderProps> = ({
    children,
}) => {
    const [state, dispatch] = useReducer(labelReducer, initialLabelState);

    useEffect(() => {
        try {
            const l = window.localStorage.getItem(LOCAL_STORAGE_SELECTED_LABEL);
            if (l) {
                const parsed: Label = JSON.parse(l);
                dispatch({ type: LabelActionType.setLabel, payload: parsed });
            }
        } catch (e) {
            dispatch({ type: LabelActionType.setLabel, payload: null });
        }
    }, []);

    useEffect(() => {
        if (state.label)
            window.localStorage.setItem(
                LOCAL_STORAGE_SELECTED_LABEL,
                JSON.stringify(state.label)
            );
    }, [state.label]);

    const setLabel = useCallback((value: Label | null) => {
        dispatch({
            type: LabelActionType.setLabel,
            payload: value || null,
        });
    }, []);

    const { label } = state;

    return (
        <LabelContext.Provider value={{ label, setLabel }}>
            {children}
        </LabelContext.Provider>
    );
};

export const useLabelContext = () => useContext<LabelContextType>(LabelContext);
