import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

import { useOktaAuth } from '@okta/okta-react';

import * as HuAuth from '@material-hu/components/composed-components/auth';
import { type ButtonProps } from '@material-hu/components/design-system/Buttons/Button';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';

import { useAuth } from 'src/contexts/JWTContext';
import { useSettings } from 'src/contexts/SettingsContext';
import useGeneralError from 'src/hooks/useGeneralError';
import { getOktaInstances } from 'src/services/authService';
import { LoginErrors, type LoginInstance } from 'src/types/login';
import { useLokaliseTranslation } from 'src/utils/i18n';

export type OktaLoginProps = ButtonProps & {
  onLogin: () => void;
  onLoginFinally: () => void;
};

export const OktaLogin = (props: OktaLoginProps) => {
  const { onLogin = () => null, onLoginFinally = () => null } = props;

  const [instances, setInstances] = useState<LoginInstance[]>([]);
  const [accessToken, setAccessToken] = useState<string | null>(null);
  const [loadingCommunities, setLoadingCommunities] = useState(false);

  const { oktaAuth } = useOktaAuth();
  const { t } = useLokaliseTranslation('authentication');
  const { enqueueSnackbar } = useHuSnackbar();
  const navigate = useNavigate();
  const showGeneralError = useGeneralError();
  const { oktaLogin } = useAuth();
  const { setPrimary, resetPrimary } = useSettings();

  useEffect(() => {
    resetPrimary();
  }, [resetPrimary]);

  useEffect(() => {
    if (window.location.hash === '#instancesOkta' && !hasInstances) {
      navigate('');
    }
  }, [window.location.hash]);

  const handleSelectInstance = async (instance: LoginInstance) => {
    try {
      navigate('');
      await login(accessToken!, instance);
      closeSelectInstanceDrawer();
    } catch (err: any) {
      const errorCode = err?.response?.data?.code;
      showGeneralError(
        err,
        t(
          errorCode === LoginErrors.SSO_MORE_THAN_ONE_USER_MATCHING_EMAIL
            ? 'ERROR_SSO_LOGIN_DUPLICATED_EMAIL'
            : 'ERROR_OKTA_LOGIN',
        ),
      );
    }
  };

  const login = async (newAccessToken: string, instance: LoginInstance) => {
    if (!oktaLogin) throw new Error('oktaLogin is not available');
    setPrimary(instance.color);
    const body = {
      accessToken: newAccessToken,
      instanceId: instance.id,
    };
    await oktaLogin(body);
  };

  const handleCancelInstance = () => {
    navigate('');
    setInstances([]);
  };

  const handleLogin = async () => {
    try {
      onLogin();
      const oktaData = await oktaAuth.token.getWithPopup({
        prompt: 'login',
      });
      const oktaAccessToken = oktaData.tokens?.accessToken?.accessToken;

      if (!oktaAccessToken) {
        throw new Error('Failed to get Okta access token');
      }

      setLoadingCommunities(true);
      const response = await getOktaInstances(oktaAccessToken);
      setLoadingCommunities(false);
      if (response.data?.length) {
        setInstances(response.data);
        setAccessToken(oktaAccessToken);

        if (response.data.length === 1) {
          await login(oktaAccessToken, response.data[0]);
        } else {
          navigate('#instancesOkta');
        }
      } else {
        enqueueSnackbar({
          title: t('OKTA_NO_COMMUNITY'),
          variant: 'error',
        });
      }
    } catch (err: any) {
      const errorCode = err?.response?.data?.code;
      showGeneralError(
        err,
        t(
          errorCode === LoginErrors.SSO_MORE_THAN_ONE_USER_MATCHING_EMAIL
            ? 'ERROR_SSO_LOGIN_DUPLICATED_EMAIL'
            : 'ERROR_OKTA_LOGIN',
        ),
      );
    } finally {
      onLoginFinally();
    }
  };

  const hasInstances = instances.length > 0;

  const {
    drawer: selectInstanceDrawer,
    showDrawer: showSelectInstanceDrawer,
    closeDrawer: closeSelectInstanceDrawer,
  } = HuAuth.useSelectIntanceDrawer({
    onClose: handleCancelInstance,
    loading: loadingCommunities,
    instances,
    onSelectInstance: (instance: { name: string; logo: string }) => {
      handleSelectInstance(instance as LoginInstance);
    },
    showSearch: false,
  });

  useEffect(() => {
    if (instances.length > 1 && window.location.hash === '#instancesOkta') {
      showSelectInstanceDrawer(true);
    }
  }, [instances, window.location.hash]);

  return (
    <>
      <HuAuth.SSOButton
        type="Okta"
        onClick={handleLogin}
      />
      {selectInstanceDrawer}
    </>
  );
};

export default OktaLogin;
