import { useMemo } from 'react';
import {
  useMutation,
  UseMutationOptions,
  useQuery,
  UseQueryOptions,
  QueryKey,
} from 'react-query';

import { AxiosResponse, AxiosError } from 'axios';

import { logEvent } from 'src/config/logging';
import { useAuth } from 'src/contexts/JWTContext';
import { loginKeys } from 'src/pages/authentication/queries';
import { sendOTP, getOTP } from 'src/services/authService';
import { EventName } from 'src/types/amplitude';
import {
  OTP,
  LoginOTPData,
  SendOTPData,
  GetOTPData,
  LoginResponse,
  OTPChannels,
} from 'src/types/login';

export const useCheckCodeMutation = (
  data: Omit<LoginOTPData, 'code'> & { instanceName: string },
  options: UseMutationOptions<
    LoginResponse,
    AxiosError<any, any>,
    { code: string; channel: OTPChannels },
    unknown
  >,
) => {
  const { onMutate = () => null, ...rest } = options;

  const { loginOTP } = useAuth();

  return useMutation<
    LoginResponse,
    AxiosError<any, any>,
    { code: string; channel: OTPChannels },
    unknown
  >(
    loginKeys.otp.login(),
    ({ code, channel }: { code: string; channel: OTPChannels }) =>
      loginOTP({ ...data, code, channel }),
    {
      onMutate: variables => {
        onMutate(variables);

        logEvent(EventName.USER_VALIDATE_CODE, {
          instanceId: data.instanceId,
          instanceName: data.instanceName,
          username: data.employeeInternalId,
          channel: variables.channel,
        });
      },
      ...rest,
    },
  );
};

export const useSendCodeMutation = (
  data: Omit<SendOTPData, 'channel'> & { instanceName: string },
  options: UseMutationOptions<
    AxiosResponse,
    AxiosError<any, any>,
    OTPChannels,
    unknown
  >,
) => {
  const { onMutate = () => null, ...rest } = options;

  return useMutation<AxiosResponse, AxiosError<any, any>, OTPChannels, unknown>(
    loginKeys.otp.send(),
    (channel: OTPChannels) => sendOTP({ ...data, channel }),
    {
      onMutate: variables => {
        onMutate(variables);

        logEvent(EventName.USER_RECEIVE_CODE, {
          instanceId: data.instanceId,
          instanceName: data.instanceName,
          username: data.employeeInternalId,
          channel: variables,
        });
      },
      ...rest,
    },
  );
};

export const useGetOTP = (
  data: GetOTPData,
  options: UseQueryOptions<
    AxiosResponse<OTP[]>,
    AxiosError<any, any>,
    AxiosResponse<OTP[]>,
    QueryKey
  >,
) => {
  const { data: otpData, isLoading } = useQuery<
    AxiosResponse<OTP[]>,
    AxiosError<any, any>
  >(
    loginKeys.otp.detail(data.instanceId, data.employeeInternalId),
    () => getOTP(data.instanceId, data.employeeInternalId),
    options,
  );

  const phoneNumber = useMemo(
    () =>
      otpData?.data?.find(val =>
        [OTPChannels.WHATSAPP, OTPChannels.SMS].includes(val.channel),
      )?.receiver,
    [otpData],
  );

  const channels = useMemo(
    () => otpData?.data?.map(val => val.channel),
    [otpData?.data],
  );

  return { phoneNumber, channels, isLoading };
};
