import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from "@nestjs/common";
import { Observable } from "rxjs";
import { finalize } from "rxjs/operators";
import { TenantConnectionRegistry } from "./tenant-connection-registry.service";
import { TenantContextStorage } from "./tenant-context.storage";

// Contraparte OBLIGATORIA de TenantGuard: el guard adquiere la conexion
// (acquire(), refCount++) pero no puede liberarla el mismo — canActivate()
// devuelve antes de que el handler corra. finalize() de rxjs se dispara en
// exito, en error Y en cancelacion (cliente que corta a mitad de request)
// por igual, asi el refCount nunca queda inflado de forma permanente — sin
// esto, cada request agotaria una unidad del pool del tenant para siempre.
//
// Se registra SIEMPRE en el mismo controller que TenantGuard, nunca uno sin
// el otro: un guard sin este interceptor filtra conexiones; este
// interceptor sin el guard no libera nada (nunca hubo un acquire que
// liberar), pero tampoco rompe nada — es un no-op seguro en ese caso.
@Injectable()
export class TenantReleaseInterceptor implements NestInterceptor {
  constructor(
    private readonly tenantRegistry: TenantConnectionRegistry,
    private readonly tenantContext: TenantContextStorage,
  ) {}

  intercept(_context: ExecutionContext, next: CallHandler): Observable<unknown> {
    return next.handle().pipe(
      finalize(() => {
        const ctx = this.tenantContext.get();
        if (ctx?.tenantId != null) {
          this.tenantRegistry.release(ctx.tenantId);
        }
      }),
    );
  }
}
