import { CONTEXT, FactoryProvider, InjectionToken, Scope } from 'graphql-modules';
import type { RegistryContext } from './../../../context';

function maskToken(token: string) {
  if (token.length > 6) {
    return token.substring(0, 3) + '*'.repeat(token.length - 6) + token.substring(token.length - 3);
  }

  return '*'.repeat(token.length);
}

export const ApiToken = new InjectionToken<string>('x-api-token');
export const ApiTokenProvider: FactoryProvider<string | undefined> = {
  provide: ApiToken,
  useFactory(context: RegistryContext) {
    context.req.log.debug('Attempt to resolve an API token from headers');
    let token: string | undefined;

    for (const headerName in context.headers) {
      if (headerName.toLowerCase() === 'x-api-token') {
        const values = context.headers[headerName];
        const singleValue = Array.isArray(values) ? values[0] : values;

        if (singleValue && singleValue !== '') {
          context.req.log.debug(
            'Found X-API-Token header (length=%d, token=%s)',
            singleValue.length,
            maskToken(singleValue),
          );
          token = singleValue;
          break;
        }
      } else if (headerName.toLowerCase() === 'authorization') {
        const values = context.headers[headerName];
        const singleValue = Array.isArray(values) ? values[0] : values;

        if (singleValue && singleValue !== '') {
          const bearer = singleValue.replace(/^Bearer\s+/i, '');

          // Skip if bearer is missing or it's JWT generated by Auth0 (not API token)
          if (bearer && bearer !== '' && !bearer.includes('.')) {
            context.req.log.debug(
              'Found Authorization header (length=%d, token=%s)',
              bearer.length,
              maskToken(bearer),
            );
            token = bearer;
            break;
          }
        }
      }
    }

    return token;
  },
  deps: [CONTEXT],
  scope: Scope.Operation,
};
