import React from 'react';
import { call, put, select } from 'redux-saga/effects';
import { post, get, del } from 'services/requests';
import { Api } from 'routes/Api';
import { handleError } from 'modules/error-handler';
import { login, userStateInterface } from 'services/auth';
import * as actions from 'lib/redux/actions/auth-actions';
import { removeCookie } from 'modules/cookies';
import { message, notification } from 'antd';
import { KeyOutlined } from '@ant-design/icons';
import { subscribeToEmailConfirmedChannel } from 'services/channels/email-confirmed-channel';
import { setUnreadMessages } from '../actions/messages-actions';
import { Action } from 'lib/types/interfaces';



export function* authLogin(action: Action): Generator {
	try {
		const res: any = yield call(() => post({
			url: Api.authLogin,
			data: action.payload
		}));

		if (res.data['unread_messages'].length) {
			yield put(setUnreadMessages({ data: res.data['unread_messages'] }));
		}

		const userState = {
			isAuthenticated: true,
			name: res.data.name,
			username: res.data.username,
			email: res.data.email,
			picture: res.data.picture,
			roles: res.data.roles,
			access_token: res.data.access_token,
			token_type: res.data.token_type,
			expires_at: res.data.expires_at,
			awebkey: res.data.awebkey,
			subscriptions: res.data.subscriptions,
			unread_messages: res.data.unread_messages,
			phone_verified: res.data.phone_verified,
			phone: res.data.phone,
		};

		yield login(userState);

	}
	catch (error) {
		// dispatch a failure action to the store with the error
		switch (error?.response?.status) {
		case 422:
			yield put(actions.failedLogIn({ error: error.response.data?.errors }));
			break;

		case 401:
			message.error('Incorrect email, username or password');
			yield put(actions.failedLogIn({ error: error.response.data?.errors }));
			break;

		default:
			yield put(actions.failedLogIn({ error: null }));
			handleError(error);
			break;
		}
	}
}


export function* signUp(action: Action): Generator {
	try {
		yield call(() => post({
			url: Api.signup,
			data: action.payload
		}));

		// dispatch a success action to the store
		yield put(actions.signedUp({ data: { status: { issigningup: false, issignedup: true, error: null } } }));
		notification.success({
			message: 'Account created!',
			description: 'Account setup! Kindly login to continue',
			placement: 'bottomRight',
			duration: 15
		});
		removeCookie('persist:root');
		yield subscribeToEmailConfirmedChannel(action.payload);
		yield put(actions.signedUp({ data: { status: { issigningup: false, issignedup: false, error: null } } }));

	}
	catch (error) {
		// dispatch a failure action to the store with the error
		if (error?.response?.status == 422) {
			return yield put(actions.failedSignUp({ error: error.response.data.errors }));
		}
		return yield put(actions.failedSignUp({ error: error }));
	}
}


export function* authLogout(): Generator {
	try {
		yield call(() => get({
			url: Api.authLogout
		}));
		// Clear access token and ID token from local storage
		// removeCookie('userState');
		removeCookie('persist:root');

		// unset user login state in store
		// step missing

		// dispatch logoutAction();
		yield put(actions.loggedOut(null));
	}
	catch (error) {
		// dispatch a failure action to the store with the error
		yield put(actions.failedLogOut({ error: error }));
		return handleError(error);
	}
}


export function* fetchAuthUser(action: Action): Generator {
	try {
		const res: any = yield call(() => get({
			url: Api.authUser
		}));

		if (res.data['unread_messages'].length) {
			yield put(setUnreadMessages({ data: res.data['unread_messages'] }));
		}

		const getState = (state): object => state.userState;
		const userState : any = yield select(getState);

		const data = {
			...userState,
			name: res.data.name,
			username: res.data.username,
			email: res.data.email,
			picture: res.data.picture,
			roles: res.data.roles,
			awebkey: res.data.awebkey,
			subscriptions: res.data.subscriptions,
			unread_messages: res.data.unread_messages,
			phone_verified: res.data.phone_verified,
			phone: res.data.phone,
		};

		yield put(actions.fetchedAuthUser({data}));

	}
	catch (error) {
		// dispatch a failure action to the store with the error
		yield put(actions.failedFetchAuthUser({ error }));
	}
}


export function* changePassword(action: Action): Generator {
	try {
		const res : any = yield call(() => post({
			url: Api.changePassword,
			data: action.payload
		}));

		yield put(actions.changedPassword({ data: res?.data }));

		notification.open({
			message: 'Password Updated',
			description: 'Your has been successfully changed',
			duration: 10
		});


	}
	catch (error) {
		// dispatch a failure action to the store with the error
		switch (error?.response?.status) {
		case 422:
			message.error(error.response?.data?.errorMessage ?? 'Check the form for validation errors');
			yield put(actions.failedChangePassword({ error: error.response.data?.errors }));
			break;

		case 403:
			message.error('Failed to change password. Kindly login and try again. Or contact support');
			yield put(actions.failedChangePassword({ error: error.response.data?.errors }));
			break;

		default:
			yield put(actions.failedChangePassword({ error: error.response.data?.errors }));
			handleError(error);
			break;
		}
	}
}


export function* resetPassword(action: Action): Generator {
	const hide = message.loading('Sending password reset request');
	try {
		const res : any = yield call(() => post({
			url: Api.resetPassword + '/create',
			data: action.payload
		}));

		notification.open({
			message: 'Password Reset Request Sent!',
			description: 'A password reset link has been sent to your email. Kindly check your email inbox and click the link to continue',
			duration: 0,
			icon: (<KeyOutlined style={{ color: '#3db83a' }} />)
		});
		yield put(actions.didResetPassword(res.data));

	}
	catch (error) {
		// dispatch a failure action to the store with the error
		switch (error?.response?.status) {
		case 422:
			message.error('Kindly check the form you submitted for errors');
			yield put(actions.failedResetPassword({ error: error.response.data?.errors }));
			break;
		case 404:
			message.error('No user found with that email');
			yield put(actions.failedResetPassword({ error: error.response.data?.errors }));
			break;
		default:
			yield put(actions.failedResetPassword({ error: error.response.data?.errors }));
			handleError(error);
			break;
		}
	}
	finally {
		hide();
	}
}


export function* authorizePasswordResetRequest(action: Action): Generator {
	try {
		const res : any = yield call(() => get({
			url: Api.resetPassword + '/find/' + action.token
		}));
		yield put(actions.authorizedPasswordResetRequest({ data: res.data }));

	}
	catch (error) {
		// dispatch a failure action to the store with the error
		switch (error?.response?.status) {
		case 404:
			message.error(error.message);
			yield put(actions.failedAuthorizePasswordResetRequest({ error: error.response.data?.errors }));
			break;
		default:
			yield put(actions.failedAuthorizePasswordResetRequest({ error: error.response.data?.errors }));
			handleError(error);
			break;
		}
	}
}


export function* sendConfirmEmailRequest(action: Action): Generator {
	try {
		const res : any = yield call(() => get({
			url: Api.activateSignup + '/' + action.token
		}));

		yield put(actions.sentConfirmEmailRequest({ data: res.data }));
		notification.open({
			message: 'Email Confirmed',
			description: 'Thank you for confirming your email',
			duration: 0
		});

	}
	catch (error) {
		// dispatch a failure action to the store with the error
		switch (error?.response?.status) {
		case 404:
			message.error(error.message);
			yield put(actions.failedSendConfirmEmailRequest({ error: error.response.data?.errors }));
			break;
		default:
			yield put(actions.failedSendConfirmEmailRequest({ error: error.response.data?.errors }));
			handleError(error);
			break;
		}
	}
}


export function* completeResetPassword(action: Action): Generator {
	try {
		const res : any = yield call(() => post({
			url: Api.resetPassword + '/reset',
			data: action.payload
		}));

		yield put(actions.completedResetPassword(res.data));
		notification.open({
			message: 'Password reset successful',
			description: 'Your password has been successful reset. Kindly login to continue',
			duration: 20
		});

	}
	catch (error) {
		// dispatch a failure action to the store with the error
		switch (error?.response?.status) {
		case 422:
			message.error('Kindly check the form you submitted for errors');
			yield put(actions.failedCompleteResetPassword({ error: error.response.data?.errors }));
			break;
		case 404:
			message.error(error.message);
			yield put(actions.failedCompleteResetPassword({ error: error.response.data?.errors }));
			break;
		default:
			yield put(actions.failedCompleteResetPassword({ error: error.response.data?.errors }));
			handleError(error);
			break;
		}
	}
}


export function* updateProfile(action: Action): Generator {
	const hide = message.loading('Updating changes');
	try {
		const res : any = yield call(() => post({
			url: Api.users + '/' + action.payload.get('username'),
			data: action.payload
		}));

		yield put(actions.updatedProfile({ data: res.data }));

		message.success('Profile Updated');
	}
	catch (error) {
		if (error.response.status == 422) {
			message.error('Kindly check the submitted from for errors', 10);
			return yield put(actions.failedUpdateProfile({ error: error.response.data.errors }));
		}

		yield put(actions.failedUpdateProfile({ error: error.message }));
		message.error('Unable to update profile at the moment');
		return handleError(error);
	}
	finally {
		hide();
	}
}


export function* freezeAccount(action): Generator {
	const hide = message.loading('Hold on while we are process your request.');
	try {
		const res: Record<string, any> = yield call(() => del({
			url: Api.users + '/' + action.username
		}));

		yield put(actions.frozeAccount({ data: res.data }));
		removeCookie('persist:root');
		message.success('Account frozen.');
		message.success('Redirecting in 6 seconds', 6);
		setTimeout(() => window.location.href = '/', 6e3);
	}
	catch (error) {
		yield put(actions.failedFreezeAccount({ error: error.message }));

		handleError(error);
	}
	finally {
		hide();
	}
}


export function* deleteAccount(action): Generator {
	const hide = message.loading('Hold on while we are process your request.');
	try {
		const res: Record<string, any> = yield call(() => del({
			url: Api.users + '/' + action.username + '/delete'
		}));

		yield put(actions.deletedAccount({ data: res.data }));
		removeCookie('persist:root');
		message.success('Account deleted.');
		message.success('Redirecting in 6 seconds', 6);
		setTimeout(() => window.location.href = '/', 6e3);
	}
	catch (error) {
		yield put(actions.failedDeleteAccount({ error: error.message }));

		handleError(error);
	}
	finally {
		hide();
	}
}


export function* subscribeToEmail(): Generator {
	const hide = message.loading('Hold on while we are process your request.');
	try {
		const res: Record<string, any> = yield call(() => post({
			url: Api.subscribeToEmail
		}));

		const
			getData = state => state.userState,
			dataToAlter = yield select(getData);

		if (dataToAlter['subscriptions'].email) {
			dataToAlter['subscriptions'].email.push(res.data);
		} else {
			dataToAlter['subscriptions'].email = [res.data];
		}

		yield put(actions.subscribedToEmail({ data: dataToAlter }));

		message.success('You are now subscribed to email notifications');
	}
	catch (error) {
		yield put(actions.failedSubscribeToEmail({ error: error.message }));

		handleError(error);
	}
	finally {
		hide();
	}
}


export function* unsubscribeFromEmail(): Generator {
	const hide = message.loading('Hold on while we are process your request.');
	try {
		yield call(() => del({
			url: Api.unsubscribeFromEmail
		}));

		const
			getData = state => state.userState;
		const dataToAlter = yield select(getData);

		dataToAlter['subscriptions'].email = [];


		yield put(actions.unsubscribedFromEmail({ data: dataToAlter }));

		message.success('You are now unsubscribed from email notifications');
	}
	catch (error) {
		yield put(actions.failedUnsubscribeFromEmail({ error: error.message }));

		message.error('Unable to unsubscribe from email notifications at this time');
	}
	finally {
		hide();
	}
}


export function* loginByGoogle(action: Action): Generator {
	try {
		const res : any = yield call(() => post({
			url: Api.authGoogleLogin,
			data: {
				user_hash: action.user_hash
			}
		}));

		if (res.data['unread_messages'].length) {
			yield put(setUnreadMessages({ data: res.data['unread_messages'] }));
		}

		const userState = {
			isAuthenticated: true,
			name: res.data.name,
			username: res.data.username,
			email: res.data.email,
			picture: res.data.picture,
			roles: res.data.roles,
			access_token: res.data.access_token,
			token_type: res.data.token_type,
			expires_at: res.data.expires_at,
			awebkey: res.data.awebkey,
			subscriptions: res.data.subscriptions,
			unread_messages: res.data.unread_messages,
			phone_verified: res.data.phone_verified,
			phone: res.data.phone,
		};

		yield login(userState);

		setTimeout(() => window.location.href = '/', 2e3);
	}
	catch (error) {
		message.error('Failed to login you in with google.');
		message.error('Please try again later');
		yield actions.failedLoginByGoogle({ error });
	}
}


export function* verifyPhone(action: Action): Generator {
	try {
		const res : any= yield call(() => post({
			url: Api.verifyPhone,
			data: action.payload
		}));

		const getData = state => state.userState;

		const userState  : any= yield select(getData);

		userState.phone_verified = 1;
		yield put(actions.verifiedPhone({ data: userState }));

		message.success('Phone number successfully verified');
		// message.success('Login again to continue');

		setTimeout(() => window.location.href = '/', 2e3);
	}
	catch (error) {
		if (error?.response?.status == 422) {
			handleError(error?.response?.data?.message, { allowNotifiy: true });
			yield put(actions.failedVerifyPhone({ error: error.response.data?.errors }));
			return;
		}
		yield put(actions.failedVerifyPhone({ error }));
	}
}


export function* resendPhoneVerificationCode(action: Action): Generator {
	try {
		const res : any = yield call(() => post({
			url: Api.verifyPhone + '/resend',
			data: action.payload
		}));

		message.success('Verification code has been resent');
		yield put(actions.resentPhoneVerificationCode({ data: res.data }));
	}
	catch (error) {
		message.error('Unable to resend code. Please try again later');
		yield put(action.failedResendPhoneVerificationCode({ error }));
	}
}


export function* changePhoneForVerification(action: Action): Generator {
	try {
		const res : any = yield call(() => post({
			url: Api.verifyPhone + '/change',
			data: action.payload
		}));

		message.success('Your phone number has been changed');
		message.success('Verification message sent to new phone number');

		yield put(actions.changedPhoneForVerification({ data: res.data }));
	}
	catch (error) {
		if (error?.response?.status == 422) {
			// handleError(error?.response?.data?.message, { allowNotifiy: true });
			yield put(actions.failedChangePhoneForVerification({ error: error.response.data?.errors }));
			return;
		}
		yield put(actions.failedChangePhoneForVerification({ error: error }));
	}
}
