import React, { useEffect, useLayoutEffect, useReducer, useRef, useState } from 'react';
import { ScrollView, View } from 'react-native';
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import ImagePicker, { Image } from 'react-native-image-crop-picker';
import { shallowEqual } from 'react-redux';

import { compareServerVersion } from '../../lib/methods/helpers';
import KeyboardView from '../../containers/KeyboardView';
import sharedStyles from '../Styles';
import scrollPersistTaps from '../../lib/methods/helpers/scrollPersistTaps';
import { showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers/info';
import StatusBar from '../../containers/StatusBar';
import { useTheme } from '../../theme';
import SafeAreaView from '../../containers/SafeAreaView';
import * as List from '../../containers/List';
import styles from './styles';
import { useAppSelector } from '../../lib/hooks';
import { getUserSelector } from '../../selectors/login';
import Avatar from '../../containers/Avatar';
import AvatarUrl from './AvatarUrl';
import Button from '../../containers/Button';
import I18n from '../../i18n';
import { ChatsStackParamList } from '../../stacks/types';
import { IAvatar } from '../../definitions';
import { Services } from '../../lib/services';
import AvatarSuggestion from './AvatarSuggestion';
import log from '../../lib/methods/helpers/log';

enum AvatarStateActions {
	CHANGE_AVATAR = 'CHANGE_AVATAR',
	RESET_USER_AVATAR = 'RESET_USER_AVATAR',
	RESET_ROOM_AVATAR = 'RESET_ROOM_AVATAR'
}

interface IReducerAction {
	type: AvatarStateActions;
	payload?: Partial<IState>;
}

interface IState extends IAvatar {
	resetUserAvatar: string;
}

const initialState = {
	data: '',
	url: '',
	contentType: '',
	service: '',
	resetUserAvatar: ''
};

function reducer(state: IState, action: IReducerAction) {
	const { type, payload } = action;
	if (type in AvatarStateActions) {
		return {
			...initialState,
			...payload
		};
	}
	return state;
}

const ChangeAvatarView = () => {
	const [state, dispatch] = useReducer(reducer, initialState);
	const [saving, setSaving] = useState(false);
	const { colors } = useTheme();
	const { userId, username, serverVersion } = useAppSelector(
		state => ({
			userId: getUserSelector(state).id,
			username: getUserSelector(state).username,
			serverVersion: state.server.version
		}),
		shallowEqual
	);
	const isDirty = useRef<boolean>(false);
	const navigation = useNavigation<StackNavigationProp<ChatsStackParamList, 'ChangeAvatarView'>>();
	const { context, titleHeader, room, t } = useRoute<RouteProp<ChatsStackParamList, 'ChangeAvatarView'>>().params;

	useLayoutEffect(() => {
		navigation.setOptions({
			title: titleHeader || I18n.t('Avatar')
		});
	}, [titleHeader, navigation]);

	useEffect(() => {
		navigation.addListener('beforeRemove', e => {
			if (!isDirty.current) {
				return;
			}

			e.preventDefault();

			showConfirmationAlert({
				title: I18n.t('Discard_changes'),
				message: I18n.t('Discard_changes_description'),
				confirmationText: I18n.t('Discard'),
				onPress: () => {
					navigation.dispatch(e.data.action);
				}
			});
		});
	}, [navigation]);

	const dispatchAvatar = (action: IReducerAction) => {
		isDirty.current = true;
		dispatch(action);
	};

	const submit = async () => {
		try {
			setSaving(true);
			console.log('🚀 ~ file: index.tsx:117 ~ submit ~ state', state);
			if (context === 'room' && room?.rid) {
				// Change Rooms Avatar
				await changeRoomsAvatar(room.rid);
			} else if (state?.url) {
				// Change User's Avatar
				await changeUserAvatar(state);
			} else if (state.resetUserAvatar) {
				// Change User's Avatar
				await resetUserAvatar();
			}
			isDirty.current = false;
		} catch (e: any) {
			log(e);
			return showErrorAlert(e.message, I18n.t('Oops'));
		} finally {
			setSaving(false);
		}
		return navigation.goBack();
	};

	const changeRoomsAvatar = async (rid: string) => {
		try {
			console.log('🚀 ~ file: index.tsx:135 ~ changeRoomsAvatar ~ rid', rid, state);
			await Services.saveRoomSettings(rid, { roomAvatar: state?.data });
		} catch (e) {
			log(e);
			return handleError(e, 'changing_avatar');
		}
	};

	const changeUserAvatar = async (avatarUpload: IAvatar) => {
		try {
			console.log('🚀 ~ file: index.tsx:144 ~ changeUserAvatar ~ avatarUpload', avatarUpload);
			await Services.setAvatarFromService(avatarUpload);
		} catch (e) {
			return handleError(e, 'changing_avatar');
		}
	};

	const resetUserAvatar = async () => {
		try {
			console.log('🚀 ~ file: index.tsx:154 ~ resetUserAvatar ~ userId', userId);
			await Services.resetAvatar(userId);
		} catch (e) {
			return handleError(e, 'changing_avatar');
		}
	};

	const handleError = (e: any, action: string) => {
		if (e.data && e.data.error.includes('[error-too-many-requests]')) {
			throw new Error(e.data.error);
		}
		if (e.error && e.error === 'error-avatar-invalid-url') {
			throw new Error(I18n.t(e.error, { url: e.details.url }));
		}
		if (I18n.isTranslated(e.error)) {
			throw new Error(I18n.t(e.error));
		}
		throw new Error(I18n.t('There_was_an_error_while_action', { action: I18n.t(action) }));
	};

	const pickImage = async () => {
		const options = {
			cropping: true,
			compressImageQuality: 0.8,
			freeStyleCropEnabled: true,
			cropperAvoidEmptySpaceAroundImage: false,
			cropperChooseText: I18n.t('Choose'),
			cropperCancelText: I18n.t('Cancel'),
			includeBase64: true
		};
		try {
			const response: Image = await ImagePicker.openPicker(options);
			dispatchAvatar({
				type: AvatarStateActions.CHANGE_AVATAR,
				payload: { url: response.path, data: `data:image/jpeg;base64,${response.data}`, service: 'upload' }
			});
		} catch (error) {
			log(error);
		}
	};

	const deletingRoomAvatar = context === 'room' && state.data === null ? {} : { rid: room?.rid };

	return (
		<KeyboardView
			style={{ backgroundColor: colors.auxiliaryBackground }}
			contentContainerStyle={sharedStyles.container}
			keyboardVerticalOffset={128}
		>
			<StatusBar />
			<SafeAreaView testID='change-avatar-view'>
				<ScrollView
					contentContainerStyle={sharedStyles.containerScrollView}
					testID='change-avatar-view-list'
					{...scrollPersistTaps}
				>
					<View style={styles.avatarContainer} testID='change-avatar-view-avatar'>
						<Avatar
							text={room?.name || state.resetUserAvatar || username}
							avatar={state?.url}
							isStatic={state?.url}
							size={120}
							type={t}
							{...deletingRoomAvatar}
						/>
					</View>
					{context === 'profile' ? (
						<AvatarUrl
							submit={value =>
								dispatchAvatar({
									type: AvatarStateActions.CHANGE_AVATAR,
									payload: { url: value, data: value, service: 'url' }
								})
							}
						/>
					) : null}
					<List.Separator style={styles.separator} />
					{context === 'profile' ? (
						<AvatarSuggestion
							resetAvatar={() =>
								dispatchAvatar({
									type: AvatarStateActions.RESET_USER_AVATAR,
									payload: { resetUserAvatar: `@${username}` }
								})
							}
							username={username}
							onPress={value =>
								dispatchAvatar({
									type: AvatarStateActions.CHANGE_AVATAR,
									payload: value
								})
							}
						/>
					) : null}

					<Button
						title={I18n.t('Upload_image')}
						type='secondary'
						disabled={saving}
						backgroundColor={colors.editAndUploadButtonAvatar}
						onPress={pickImage}
						testID='change-avatar-view-logout-other-locations'
					/>
					{context === 'room' && serverVersion && compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '3.6.0') ? (
						<Button
							title={I18n.t('Delete_image')}
							type='primary'
							disabled={saving}
							backgroundColor={colors.dangerColor}
							onPress={() => dispatchAvatar({ type: AvatarStateActions.RESET_ROOM_AVATAR, payload: { data: null } })}
							testID='change-avatar-view-delete-my-account'
						/>
					) : null}
					<Button
						title={I18n.t('Save')}
						disabled={!isDirty.current || saving}
						type='primary'
						loading={saving}
						onPress={submit}
						testID='change-avatar-view-submit'
					/>
				</ScrollView>
			</SafeAreaView>
		</KeyboardView>
	);
};

export default ChangeAvatarView;
