import { InjectionToken, inject } from '@angular/core';
import { HttpInterceptorFn } from '@angular/common/http';

export interface AuthTokenSource {
  getToken(): string | null;
}

export const AUTH_TOKEN_SOURCE = new InjectionToken<AuthTokenSource>('AUTH_TOKEN_SOURCE');

/** Exact origins trusted to receive credentials, for example https://api.example.com. */
export const AUTH_ALLOWED_ORIGINS = new InjectionToken<readonly string[]>(
  'AUTH_ALLOWED_ORIGINS',
  { factory: () => [] }
);

/** Public URL prefixes that must never receive a token. */
export const AUTH_PUBLIC_URL_PREFIXES = new InjectionToken<readonly string[]>(
  'AUTH_PUBLIC_URL_PREFIXES',
  { factory: () => ['/assets/', '/public/'] }
);

export const authTokenInterceptor: HttpInterceptorFn = (request, next) => {
  const publicPrefixes = inject(AUTH_PUBLIC_URL_PREFIXES);
  if (publicPrefixes.some((prefix) => request.url.startsWith(prefix))) {
    return next(request);
  }

  if (!isAllowedDestination(request.url, inject(AUTH_ALLOWED_ORIGINS))) {
    return next(request);
  }

  const token = inject(AUTH_TOKEN_SOURCE).getToken();
  if (!token) {
    return next(request);
  }

  return next(request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }));
};

function isAllowedDestination(url: string, allowedOrigins: readonly string[]): boolean {
  if (url.startsWith('/') && !url.startsWith('//')) {
    return true;
  }

  try {
    return allowedOrigins.includes(new URL(url).origin);
  } catch {
    return false;
  }
}
