/**
 * Observability wiring for the BFF (per ADR-0012).
 *
 * Composes:
 *  - `nestjs-cls` for request-scoped context. v1 stores `request_id`
 *    (UUID per inbound request); `session_id`, `user_id_hash`, and
 *    `audience` keys are reserved for future ADR-0009 / ADR-0010
 *    work and are populated by guards/interceptors as those modules
 *    land.
 *  - `nestjs-pino` for structured JSON logs. In dev (`NODE_ENV !==
 *    'production'`) we pipe through `pino-pretty` so the developer
 *    sees colourised, human-readable lines on stdout. In prod the
 *    raw JSON output is shipped via the container runtime's stdout
 *    pipeline (per ADR-0012 §"stdout + OTLP shipping").
 *
 * Trace ↔ log correlation: handled outside this module by
 * `@opentelemetry/instrumentation-pino` (loaded in `tracing.ts`),
 * which auto-injects `trace_id` / `span_id` into every Pino log
 * record from the active OTel context.
 */

import { Module } from '@nestjs/common';
import { ClsModule } from 'nestjs-cls';
import { LoggerModule } from 'nestjs-pino';
import { randomUUID } from 'node:crypto';

const isProduction = process.env['NODE_ENV'] === 'production';
const logLevel = process.env['LOG_LEVEL'] ?? (isProduction ? 'info' : 'debug');

@Module({
  imports: [
    ClsModule.forRoot({
      global: true,
      middleware: {
        mount: true,
        generateId: true,
        // UUID v4 per request — exposed to logs as `request_id` and
        // available everywhere via `cls.get('request_id')`. Stored
        // under the conventional `id` key by nestjs-cls; we
        // surface it through Pino's `customProps` below.
        idGenerator: () => randomUUID(),
      },
    }),
    LoggerModule.forRoot({
      pinoHttp: {
        level: logLevel,
        // Pretty-print only in dev. In prod the JSON stream is
        // consumed by the container runtime / Collector.
        ...(isProduction
          ? {}
          : {
              transport: {
                target: 'pino-pretty',
                options: {
                  singleLine: true,
                  translateTime: 'SYS:HH:MM:ss.l',
                },
              },
            }),
        // Hide some noise that has nothing to do with the work being
        // done. Health-check pings would drown out everything else.
        autoLogging: {
          ignore: (req) => req.url === '/api/health' || req.url === '/health',
        },
        // Re-key the request id so it surfaces under `request_id`
        // (snake_case, ADR-0012 convention) instead of pino's
        // default `req.id` / `reqId`.
        customProps: () => ({}),
        genReqId: (req) => {
          // Honour an inbound `X-Request-Id` header when present —
          // useful for end-to-end tracing across systems that propagate
          // it. Otherwise generate a fresh UUID v4. The same id is
          // used by the CLS middleware above (Nest-Pino integrates
          // with nestjs-cls automatically when both modules are
          // imported).
          const incoming = req.headers['x-request-id'];
          return typeof incoming === 'string' && incoming.length > 0 ? incoming : randomUUID();
        },
      },
    }),
  ],
})
export class ObservabilityModule {}
