import { Inject, Injectable } from '@nestjs/common';
import { Prisma, User } from '@prisma/client';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { PrismaService } from 'nestjs-prisma';
import { Logger } from 'winston';

import { ConfigService } from '@nestjs/config';
import * as path from 'path';

@Injectable()
export class UserService {
  constructor(
    private prisma: PrismaService,
    private readonly config: ConfigService,
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
  ) {
    this.logger = this.logger.child({
      file: path.basename(__filename),
    });
  }

  async createOne(userCreateArgs: Prisma.UserCreateArgs) {
    return await this.prisma.user.create(userCreateArgs);
  }

  async createMany(data: Prisma.UserCreateManyArgs['data']) {
    return await this.prisma.user.createMany({
      data,
      skipDuplicates: true,
    });
  }

  async findMany(
    userFindManyArgs: Prisma.UserFindManyArgs,
  ): Promise<{ itemCount: number; entities: User[] }> {
    const itemCount = await this.prisma.user.count({
      where: userFindManyArgs.where,
    });
    const entities = await this.prisma.user.findMany(userFindManyArgs);
    return { itemCount, entities };
  }

  async findUnique(id: number, select: Prisma.UserFindUniqueArgs['select']) {
    return await this.prisma.user.findUnique({
      where: { id: id },
      select,
    });
  }

  async updateMany(userUpdateManyArgs: Prisma.UserUpdateManyArgs) {
    return await this.prisma.user.updateMany(userUpdateManyArgs);
  }

  async updateUnique(id: number, data: Prisma.UserUpdateManyArgs['data']) {
    return await this.prisma.user.update({
      where: { id: id },
      data,
    });
  }

  async deleteMany(userDeleteManyArgs: Prisma.UserDeleteManyArgs) {
    return await this.prisma.user.deleteMany(userDeleteManyArgs);
  }

  async deleteUnique(id: number) {
    await this.prisma.user.delete({
      where: { id: id },
    });
    return { count: 1 };
  }

  async count(userCountArgs?: Prisma.UserCountArgs) {
    return await this.prisma.user.count(userCountArgs);
  }

  async groupBy(userGroupByArgs: Prisma.UserGroupByArgs) {
    return await this.prisma.user.groupBy(userGroupByArgs as any);
  }

  async aggregate(userAggregateArgs: Prisma.UserAggregateArgs) {
    return await this.prisma.user.aggregate(userAggregateArgs);
  }

  async findByApiKey(key: string): Promise<User | null> {
    const record = await this.prisma.user.findFirst({
      where: { apiKey: key, isApiKey: true },
    });
    if (record) {
      // async update lastUsedAt - fire and forget
      this.prisma.user
        .update({
          where: { userid: record.userid },
          data: { lastUsedAt: new Date() },
        })
        .catch(() => {});
    }
    return record;
  }

  static maskApiKey(key: string | null): string {
    if (!key || key.length <= 8) return key || '';
    return key.substring(0, 8) + '****';
  }
}
