import type { PrismaClient, User } from '@prisma/client';

/** User without the passwordHash field — safe for API responses. */
export type SafeUser = Omit<User, 'passwordHash'>;

export interface IUserRepository {
  findAll(): Promise<SafeUser[]>;
  findById(id: string): Promise<SafeUser | null>;
  /** Like findById but includes the passwordHash — used by password verification. */
  findByIdWithHash(id: string): Promise<User | null>;
  findByEmail(email: string, includeHash?: boolean): Promise<SafeUser | null> | Promise<User | null>;
  create(data: { email: string; passwordHash: string; name?: string; role?: string }): Promise<SafeUser>;
  update(id: string, data: { name?: string; role?: string; passwordHash?: string }): Promise<SafeUser>;
  delete(id: string): Promise<void>;
  count(): Promise<number>;
}

/** Fields to select when passwordHash must be excluded. */
const safeSelect = {
  id: true,
  email: true,
  name: true,
  role: true,
  provider: true,
  externalId: true,
  version: true,
  createdAt: true,
  updatedAt: true,
} as const;

export class UserRepository implements IUserRepository {
  constructor(private readonly prisma: PrismaClient) {}

  async findAll(): Promise<SafeUser[]> {
    return this.prisma.user.findMany({
      select: safeSelect,
      orderBy: { email: 'asc' },
    });
  }

  async findById(id: string): Promise<SafeUser | null> {
    return this.prisma.user.findUnique({
      where: { id },
      select: safeSelect,
    });
  }

  async findByIdWithHash(id: string): Promise<User | null> {
    return this.prisma.user.findUnique({ where: { id } });
  }

  async findByEmail(email: string, includeHash?: boolean): Promise<User | SafeUser | null> {
    if (includeHash === true) {
      return this.prisma.user.findUnique({ where: { email } });
    }
    return this.prisma.user.findUnique({
      where: { email },
      select: safeSelect,
    });
  }

  async create(data: { email: string; passwordHash: string; name?: string; role?: string }): Promise<SafeUser> {
    const createData: Record<string, unknown> = {
      email: data.email,
      passwordHash: data.passwordHash,
    };
    if (data.name !== undefined) createData['name'] = data.name;
    if (data.role !== undefined) createData['role'] = data.role;

    return this.prisma.user.create({
      data: createData as Parameters<PrismaClient['user']['create']>[0]['data'],
      select: safeSelect,
    });
  }

  async update(id: string, data: { name?: string; role?: string; passwordHash?: string }): Promise<SafeUser> {
    const updateData: Record<string, unknown> = {};
    if (data.name !== undefined) updateData['name'] = data.name;
    if (data.role !== undefined) updateData['role'] = data.role;
    if (data.passwordHash !== undefined) updateData['passwordHash'] = data.passwordHash;
    return this.prisma.user.update({
      where: { id },
      data: updateData,
      select: safeSelect,
    });
  }

  async delete(id: string): Promise<void> {
    await this.prisma.user.delete({ where: { id } });
  }

  async count(): Promise<number> {
    return this.prisma.user.count();
  }
}
