import React, { createContext, ReactElement, useContext, useMemo, useReducer } from 'react';

import { IEmoji } from '../../definitions';
import { IAutocompleteBase, TMicOrSend } from './interfaces';
import { animateNextTransition } from '../../lib/methods/helpers';

type TMessageComposerContextApi = {
	setHeight: (keyboardHeight: number, trackingViewHeight: number) => void;
	openEmojiKeyboard(): void;
	closeEmojiKeyboard(): void;
	openSearchEmojiKeyboard(): void;
	closeSearchEmojiKeyboard(): void;
	setFocused(focused: boolean): void;
	setMicOrSend(micOrSend: TMicOrSend): void;
	setMarkdownToolbar(showMarkdownToolbar: boolean): void;
	setAlsoSendThreadToChannel(alsoSendThreadToChannel: boolean): void;
	setRecordingAudio(recordingAudio: boolean): void;
	setAutocompleteParams(params: IAutocompleteBase): void;
};

const FocusedContext = createContext<State['focused']>({} as State['focused']);
const MicOrSendContext = createContext<State['micOrSend']>({} as State['micOrSend']);
const ShowMarkdownToolbarContext = createContext<State['showMarkdownToolbar']>({} as State['showMarkdownToolbar']);
const ShowEmojiKeyboardContext = createContext<State['showEmojiKeyboard']>({} as State['showEmojiKeyboard']);
const ShowEmojiSearchbarContext = createContext<State['showEmojiSearchbar']>({} as State['showEmojiSearchbar']);
const KeyboardHeightContext = createContext<State['keyboardHeight']>({} as State['keyboardHeight']);
const TrackingViewHeightContext = createContext<State['trackingViewHeight']>({} as State['trackingViewHeight']);
const AlsoSendThreadToChannelContext = createContext<State['alsoSendThreadToChannel']>({} as State['alsoSendThreadToChannel']);
const RecordingAudioContext = createContext<State['recordingAudio']>({} as State['recordingAudio']);
const AutocompleteParamsContext = createContext<State['autocompleteParams']>({} as State['autocompleteParams']);
const MessageComposerContextApi = createContext<TMessageComposerContextApi>({} as TMessageComposerContextApi);

export const useMessageComposerApi = (): TMessageComposerContextApi => useContext(MessageComposerContextApi);
export const useFocused = (): State['focused'] => useContext(FocusedContext);
export const useMicOrSend = (): State['micOrSend'] => useContext(MicOrSendContext);
export const useShowMarkdownToolbar = (): State['showMarkdownToolbar'] => useContext(ShowMarkdownToolbarContext);
export const useShowEmojiKeyboard = (): State['showEmojiKeyboard'] => useContext(ShowEmojiKeyboardContext);
export const useShowEmojiSearchbar = (): State['showEmojiSearchbar'] => useContext(ShowEmojiSearchbarContext);
export const useKeyboardHeight = (): State['keyboardHeight'] => useContext(KeyboardHeightContext);
export const useTrackingViewHeight = (): State['trackingViewHeight'] => useContext(TrackingViewHeightContext);
export const useAlsoSendThreadToChannel = (): State['alsoSendThreadToChannel'] => useContext(AlsoSendThreadToChannelContext);
export const useRecordingAudio = (): State['recordingAudio'] => useContext(RecordingAudioContext);
export const useAutocompleteParams = (): State['autocompleteParams'] => useContext(AutocompleteParamsContext);

// TODO: rename
type TMessageInnerContext = {
	sendMessage(): void;
	onEmojiSelected(emoji: IEmoji): void;
	// TODO: action should be required
	closeEmojiKeyboardAndAction(action?: Function, params?: any): void;
};

// TODO: rename
export const MessageInnerContext = createContext<TMessageInnerContext>({
	sendMessage: () => {},
	onEmojiSelected: () => {},
	closeEmojiKeyboardAndAction: () => {}
});

type State = {
	showEmojiKeyboard: boolean;
	showEmojiSearchbar: boolean;
	focused: boolean;
	trackingViewHeight: number;
	keyboardHeight: number;
	micOrSend: TMicOrSend;
	showMarkdownToolbar: boolean;
	alsoSendThreadToChannel: boolean;
	recordingAudio: boolean;
	autocompleteParams: IAutocompleteBase;
};

type Actions =
	| { type: 'updateEmojiKeyboard'; showEmojiKeyboard: boolean }
	| { type: 'updateEmojiSearchbar'; showEmojiSearchbar: boolean }
	| { type: 'updateFocused'; focused: boolean }
	| { type: 'updateHeight'; trackingViewHeight: number; keyboardHeight: number }
	| { type: 'openEmojiKeyboard' }
	| { type: 'closeEmojiKeyboard' }
	| { type: 'openSearchEmojiKeyboard' }
	| { type: 'closeSearchEmojiKeyboard' }
	| { type: 'setMicOrSend'; micOrSend: TMicOrSend }
	| { type: 'setMarkdownToolbar'; showMarkdownToolbar: boolean }
	| { type: 'setAlsoSendThreadToChannel'; alsoSendThreadToChannel: boolean }
	| { type: 'setRecordingAudio'; recordingAudio: boolean }
	| { type: 'setAutocompleteParams'; params: IAutocompleteBase };

const reducer = (state: State, action: Actions): State => {
	switch (action.type) {
		case 'updateEmojiKeyboard':
			return { ...state, showEmojiKeyboard: action.showEmojiKeyboard };
		case 'updateEmojiSearchbar':
			return { ...state, showEmojiSearchbar: action.showEmojiSearchbar };
		case 'updateFocused':
			animateNextTransition();
			return { ...state, focused: action.focused };
		case 'updateHeight':
			return { ...state, trackingViewHeight: action.trackingViewHeight, keyboardHeight: action.keyboardHeight };
		case 'openEmojiKeyboard':
			return { ...state, showEmojiKeyboard: true, showEmojiSearchbar: false };
		case 'openSearchEmojiKeyboard':
			return { ...state, showEmojiKeyboard: false, showEmojiSearchbar: true };
		case 'closeEmojiKeyboard':
			return { ...state, showEmojiKeyboard: false, showEmojiSearchbar: false };
		case 'closeSearchEmojiKeyboard':
			return { ...state, showEmojiSearchbar: false };
		case 'setMicOrSend':
			return { ...state, micOrSend: action.micOrSend };
		case 'setMarkdownToolbar':
			animateNextTransition();
			return { ...state, showMarkdownToolbar: action.showMarkdownToolbar };
		case 'setAlsoSendThreadToChannel':
			return { ...state, alsoSendThreadToChannel: action.alsoSendThreadToChannel };
		case 'setRecordingAudio':
			animateNextTransition();
			return { ...state, recordingAudio: action.recordingAudio };
		case 'setAutocompleteParams':
			return { ...state, autocompleteParams: action.params };
	}
};

export const MessageComposerProvider = ({ children }: { children: ReactElement }): ReactElement => {
	const [state, dispatch] = useReducer(reducer, { keyboardHeight: 0, autocompleteParams: { text: '', type: null } } as State);

	const api = useMemo(() => {
		const setFocused: TMessageComposerContextApi['setFocused'] = focused => dispatch({ type: 'updateFocused', focused });

		const setHeight: TMessageComposerContextApi['setHeight'] = (keyboardHeight, trackingViewHeight) =>
			dispatch({ type: 'updateHeight', keyboardHeight, trackingViewHeight });

		const openEmojiKeyboard = () => dispatch({ type: 'openEmojiKeyboard' });

		const closeEmojiKeyboard = () => dispatch({ type: 'closeEmojiKeyboard' });

		const openSearchEmojiKeyboard = () => dispatch({ type: 'openSearchEmojiKeyboard' });

		const closeSearchEmojiKeyboard = () => dispatch({ type: 'closeSearchEmojiKeyboard' });

		const setMicOrSend: TMessageComposerContextApi['setMicOrSend'] = micOrSend => dispatch({ type: 'setMicOrSend', micOrSend });

		const setMarkdownToolbar: TMessageComposerContextApi['setMarkdownToolbar'] = showMarkdownToolbar =>
			dispatch({ type: 'setMarkdownToolbar', showMarkdownToolbar });

		const setAlsoSendThreadToChannel: TMessageComposerContextApi['setAlsoSendThreadToChannel'] = alsoSendThreadToChannel =>
			dispatch({ type: 'setAlsoSendThreadToChannel', alsoSendThreadToChannel });

		const setRecordingAudio: TMessageComposerContextApi['setRecordingAudio'] = recordingAudio =>
			dispatch({ type: 'setRecordingAudio', recordingAudio });

		const setAutocompleteParams: TMessageComposerContextApi['setAutocompleteParams'] = params =>
			dispatch({ type: 'setAutocompleteParams', params });

		return {
			setFocused,
			setHeight,
			openEmojiKeyboard,
			closeEmojiKeyboard,
			openSearchEmojiKeyboard,
			closeSearchEmojiKeyboard,
			setMicOrSend,
			setMarkdownToolbar,
			setAlsoSendThreadToChannel,
			setRecordingAudio,
			setAutocompleteParams
		};
	}, []);

	return (
		<MessageComposerContextApi.Provider value={api}>
			<ShowEmojiKeyboardContext.Provider value={state.showEmojiKeyboard}>
				<ShowEmojiSearchbarContext.Provider value={state.showEmojiSearchbar}>
					<FocusedContext.Provider value={state.focused}>
						<KeyboardHeightContext.Provider value={state.keyboardHeight}>
							<TrackingViewHeightContext.Provider value={state.trackingViewHeight}>
								<ShowMarkdownToolbarContext.Provider value={state.showMarkdownToolbar}>
									<AlsoSendThreadToChannelContext.Provider value={state.alsoSendThreadToChannel}>
										<RecordingAudioContext.Provider value={state.recordingAudio}>
											<AutocompleteParamsContext.Provider value={state.autocompleteParams}>
												<MicOrSendContext.Provider value={state.micOrSend}>{children}</MicOrSendContext.Provider>
											</AutocompleteParamsContext.Provider>
										</RecordingAudioContext.Provider>
									</AlsoSendThreadToChannelContext.Provider>
								</ShowMarkdownToolbarContext.Provider>
							</TrackingViewHeightContext.Provider>
						</KeyboardHeightContext.Provider>
					</FocusedContext.Provider>
				</ShowEmojiSearchbarContext.Provider>
			</ShowEmojiKeyboardContext.Provider>
		</MessageComposerContextApi.Provider>
	);
};
