import { Injectable, BadRequestException } from "@nestjs/common";
import type { User as PrismaUser } from "@prisma/client";
import { PrismaService } from "@bff/infra/database/prisma.service.js";
import { normalizeAndValidateEmail } from "@customer-portal/domain/common";
import { extractErrorMessage } from "@bff/core/utils/error.util.js";
import { parseUuidOrThrow } from "@bff/core/utils/validation.util.js";

const INVALID_USER_ID_FORMAT = "Invalid user ID format";

type AuthUpdatableFields = Pick<
  PrismaUser,
  "passwordHash" | "failedLoginAttempts" | "lastLoginAt" | "lockedUntil"
>;

@Injectable()
export class UserAuthRepository {
  constructor(private readonly prisma: PrismaService) {}

  async findByEmail(email: string): Promise<PrismaUser | null> {
    const normalized = normalizeAndValidateEmail(email);
    try {
      return await this.prisma.user.findUnique({ where: { email: normalized } });
    } catch (error) {
      throw new BadRequestException(
        `Unable to retrieve user by email: ${extractErrorMessage(error)}`
      );
    }
  }

  async findById(id: string): Promise<PrismaUser | null> {
    const validId = parseUuidOrThrow(id, INVALID_USER_ID_FORMAT);
    try {
      return await this.prisma.user.findUnique({ where: { id: validId } });
    } catch (error) {
      throw new BadRequestException(`Unable to retrieve user by id: ${extractErrorMessage(error)}`);
    }
  }

  async create(data: Partial<PrismaUser>): Promise<PrismaUser> {
    if (!data.email) {
      throw new BadRequestException("Email is required to create a user");
    }

    const normalizedEmail = normalizeAndValidateEmail(data.email);

    try {
      return await this.prisma.user.create({
        data: {
          ...data,
          email: normalizedEmail,
        },
      });
    } catch (error) {
      throw new BadRequestException(`Unable to create user: ${extractErrorMessage(error)}`);
    }
  }

  async updateAuthState(id: string, data: Partial<AuthUpdatableFields>): Promise<void> {
    const validId = parseUuidOrThrow(id, INVALID_USER_ID_FORMAT);

    try {
      await this.prisma.user.update({
        where: { id: validId },
        data,
      });
    } catch (error) {
      throw new BadRequestException(
        `Unable to update user auth state: ${extractErrorMessage(error)}`
      );
    }
  }

  async updateEmail(id: string, email: string): Promise<void> {
    const validId = parseUuidOrThrow(id, INVALID_USER_ID_FORMAT);
    const normalized = normalizeAndValidateEmail(email);
    try {
      await this.prisma.user.update({
        where: { id: validId },
        data: { email: normalized },
      });
    } catch (error) {
      throw new BadRequestException(`Unable to update user email: ${extractErrorMessage(error)}`);
    }
  }
}
