import type { HttpHandlerFn, HttpInterceptorFn, HttpRequest } from '@angular/common/http';
import { inject } from '@angular/core';
import { AUTH_BFF_BASE_URL, AUTH_CSRF_COOKIE_NAME } from './auth.config';

/**
 * Double-submit CSRF helper interceptor (per ADR-0009). Reads the
 * BFF-issued `__Host-portal_csrf` cookie (or its dev twin
 * `portal_csrf`) and copies the value into an `X-CSRF-Token` header
 * on every BFF request whose method mutates state.
 *
 * GET / HEAD / OPTIONS pass through without a header — the BFF
 * skips CSRF on safe methods anyway, and adding the header would
 * just be noise.
 *
 * Non-BFF origins pass through untouched. Same posture as the other
 * BFF-only interceptors in this lib.
 *
 * If the cookie is missing (anonymous, freshly-cleared session,
 * etc.), the request goes through without the header — the BFF
 * skips CSRF on anonymous requests, and on the authenticated path
 * the BFF will answer 403 which the SPA can surface as "please
 * sign in again".
 */
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);

export const csrfInterceptor: HttpInterceptorFn = (
  req: HttpRequest<unknown>,
  next: HttpHandlerFn,
) => {
  const bffBaseUrl = inject(AUTH_BFF_BASE_URL);
  const cookieName = inject(AUTH_CSRF_COOKIE_NAME);

  if (!req.url.startsWith(bffBaseUrl)) return next(req);
  if (SAFE_METHODS.has(req.method.toUpperCase())) return next(req);

  const token = readCookie(cookieName);
  if (!token) return next(req);

  return next(req.clone({ setHeaders: { 'X-CSRF-Token': token } }));
};

function readCookie(name: string): string | null {
  // `document.cookie` is the only browser API to read non-HttpOnly
  // cookies. The CSRF cookie is deliberately *not* HttpOnly so we
  // can do exactly this; the session cookie remains HttpOnly.
  const cookies = typeof document !== 'undefined' ? document.cookie : '';
  for (const raw of cookies.split(';')) {
    const eq = raw.indexOf('=');
    if (eq < 0) continue;
    const key = raw.slice(0, eq).trim();
    if (key === name) {
      return decodeURIComponent(raw.slice(eq + 1));
    }
  }
  return null;
}
