'use client';

import { useCallback } from 'react';

import type {
  Provider,
  SignInWithOAuthCredentials,
} from '@supabase/supabase-js';

import { useSignInWithProvider } from '@kit/supabase/hooks/use-sign-in-with-provider';
import { If } from '@kit/ui/if';
import { LoadingOverlay } from '@kit/ui/loading-overlay';
import { Trans } from '@kit/ui/trans';

import { AuthErrorAlert } from './auth-error-alert';
import { AuthProviderButton } from './auth-provider-button';

/**
 * @name OAUTH_SCOPES
 * @description
 * The OAuth scopes are used to specify the permissions that the application is requesting from the user.
 *
 * Please add your OAuth providers here and the scopes you want to use.
 *
 * @see https://supabase.com/docs/guides/auth/social-login
 */
const OAUTH_SCOPES: Partial<Record<Provider, string>> = {
  // azure: 'email',
  // keycloak: 'openid',
  // add your OAuth providers here
};

export const OauthProviders: React.FC<{
  inviteToken?: string;
  shouldCreateUser: boolean;
  enabledProviders: Provider[];
  queryParams?: Record<string, string>;

  paths: {
    callback: string;
    returnPath: string;
  };
}> = (props) => {
  const signInWithProviderMutation = useSignInWithProvider();

  // we make the UI "busy" until the next page is fully loaded
  const loading = signInWithProviderMutation.isPending;

  const onSignInWithProvider = useCallback(
    async (signInRequest: () => Promise<unknown>) => {
      const credential = await signInRequest();

      if (!credential) {
        return Promise.reject(new Error(`No credential returned`));
      }
    },
    [],
  );

  const enabledProviders = props.enabledProviders;

  if (!enabledProviders?.length) {
    return null;
  }

  return (
    <>
      <If condition={loading}>
        <LoadingOverlay />
      </If>

      <div className={'flex w-full flex-1 flex-col space-y-3'}>
        <div className={'flex-col space-y-2'}>
          {enabledProviders.map((provider) => {
            return (
              <AuthProviderButton
                key={provider}
                providerId={provider}
                onClick={() => {
                  const origin = window.location.origin;
                  const queryParams = new URLSearchParams();

                  if (props.paths.returnPath) {
                    queryParams.set('next', props.paths.returnPath);
                  }

                  if (props.inviteToken) {
                    queryParams.set('invite_token', props.inviteToken);
                  }

                  // signicat/keycloak will not allow redirect-uri with changing query params
                  const INCLUDE_QUERY_PARAMS = false as boolean;

                  const redirectPath = INCLUDE_QUERY_PARAMS
                    ? [props.paths.callback, queryParams.toString()].join('?')
                    : props.paths.callback;

                  const redirectTo = [origin, redirectPath].join('');
                  const scopes = OAUTH_SCOPES[provider] ?? undefined;

                  const credentials = {
                    provider,
                    options: {
                      redirectTo,
                      queryParams: props.queryParams,
                      scopes,
                      // skipBrowserRedirect: false,
                    },
                  } satisfies SignInWithOAuthCredentials;

                  return onSignInWithProvider(() =>
                    signInWithProviderMutation.mutateAsync(credentials),
                  );
                }}
              >
                {provider === 'keycloak' ? (
                  <Trans i18nKey={'auth:signInWithKeycloak'} />
                ) : (
                  <Trans
                    i18nKey={'auth:signInWithProvider'}
                    values={{
                      provider: getProviderName(provider),
                    }}
                  />
                )}
              </AuthProviderButton>
            );
          })}
        </div>

        <AuthErrorAlert error={signInWithProviderMutation.error} />
      </div>
    </>
  );
};

function getProviderName(providerId: string) {
  const capitalize = (value: string) =>
    value.slice(0, 1).toUpperCase() + value.slice(1);

  if (providerId.endsWith('.com')) {
    return capitalize(providerId.split('.com')[0]!);
  }

  return capitalize(providerId);
}
