import { Injectable, Inject, InternalServerErrorException } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { UsersService } from "@bff/modules/users/application/users.service.js";
import { AuditService, AuditAction } from "@bff/infra/audit/audit.service.js";
import { AuthTokenService } from "../../token/token.service.js";
import { mapPrismaUserToDomain } from "@bff/infra/mappers/index.js";
import type { AuthResultInternal } from "@bff/modules/auth/auth.types.js";

export interface GenerateAuthResultParams {
  userId: string;
  email: string;
  auditSource: string;
  auditDetails?: Record<string, unknown>;
}

/**
 * Step: Generate authentication result (tokens + profile).
 *
 * Loads the freshly created user, logs an audit event,
 * and generates a JWT access/refresh token pair.
 *
 * No rollback — stateless token generation.
 */
@Injectable()
export class GenerateAuthResultStep {
  constructor(
    private readonly usersService: UsersService,
    private readonly auditService: AuditService,
    private readonly authTokenService: AuthTokenService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  async execute(params: GenerateAuthResultParams): Promise<AuthResultInternal> {
    const { userId, email, auditSource, auditDetails } = params;

    // Load fresh user from DB
    const freshUser = await this.usersService.findByIdInternal(userId);
    if (!freshUser) {
      throw new InternalServerErrorException("Failed to load created user");
    }

    // Log audit event
    await this.auditService.logAuthEvent(AuditAction.SIGNUP, userId, {
      email,
      source: auditSource,
      ...auditDetails,
    });

    // Generate token pair
    const profile = mapPrismaUserToDomain(freshUser);
    const tokens = await this.authTokenService.generateTokenPair({
      id: profile.id,
      email: profile.email,
    });

    this.logger.log({ userId, email }, "Auth result generated");

    return { user: profile, tokens };
  }
}
