import { Request, Response, NextFunction } from 'express';
import { BadRequestError } from '../httpErrors.js';

declare global {
  // eslint-disable-next-line @typescript-eslint/no-namespace
  namespace Express {
    interface Locals {
      credentials: Credentials;
    }
  }
}

/**
 * A single rate-limit layer specification: the same `{ reqPerPeriod, periodMs }` knobs a
 * keuf layer takes. Both fields are required — an override entry fully defines a layer, so
 * what is set is exactly what runs (no partial merge, no hidden defaults).
 */
export type RateLimitValue = { reqPerPeriod: number; periodMs: number };

/**
 * Per-credential rate-limit override, keyed by an integration-defined layer name (e.g. an
 * endpoint type or tier). Each entry fully defines that layer; layers with no entry fall back
 * to the integration's own default. Each integration narrows the keys it recognizes.
 */
export type RateLimitOverride = Record<string, RateLimitValue>;

/**
 * The credentials object passed to every handler function.
 *
 * It contains the parsed credentials payload associated with the request through the X-Unito-Credentials header.
 */
export type Credentials = {
  /**
   * The access token for the provider.
   */
  accessToken?: string;
  /**
   * The id of the unito credential record.
   *
   * This is not available on the initial call to /me before the creation of the credential.
   */
  unitoCredentialId?: string;
  /**
   * The id of the unito user record.
   */
  unitoUserId?: string;
  /**
   * Per-credential rate-limit override, injected by platformServer from the credential's
   * `rateLimitOverride` column. See {@link RateLimitOverride}.
   */
  rateLimitOverride?: RateLimitOverride;
  [keys: string]: unknown;
};

const CREDENTIALS_HEADER = 'X-Unito-Credentials';

function extractCredentials(req: Request, res: Response, next: NextFunction) {
  const credentialsHeader = req.header(CREDENTIALS_HEADER);

  if (credentialsHeader) {
    let credentials: Credentials;

    try {
      credentials = JSON.parse(Buffer.from(credentialsHeader, 'base64').toString('utf8'));
    } catch {
      throw new BadRequestError(`Malformed HTTP header ${CREDENTIALS_HEADER}`);
    }

    res.locals.credentials = credentials;

    if (credentials.unitoCredentialId) {
      res.locals.logger?.decorate({ credentialId: credentials.unitoCredentialId });
    }

    if (credentials.unitoUserId) {
      res.locals.logger?.decorate({ userId: credentials.unitoUserId });
    }
  }

  next();
}

export default extractCredentials;
