import { Inject, Injectable } from '@nestjs/common';
import { Prisma, Resource } 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 { createSafeLogData } from '../../lib/safe-log.util';

@Injectable()
export class ResourceService {
  constructor(
    private prisma: PrismaService,
    private readonly config: ConfigService,
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
  ) {}

  async createOne(resourceCreateArgs: Prisma.ResourceCreateArgs) {
    this.logger.info(
      '[Resource] Creating resource',
      createSafeLogData({
        operation: 'CREATE',
        table: 'resource',
        data: resourceCreateArgs.data,
      }),
    );
    const result = await this.prisma.resource.create(resourceCreateArgs);
    this.logger.info(
      '[Resource] Resource created successfully',
      createSafeLogData({
        operation: 'CREATE',
        table: 'resource',
        result: result,
      }),
    );
    return result;
  }

  async createMany(data: Prisma.ResourceCreateManyArgs['data']) {
    this.logger.info(
      '[Resource] Creating multiple resources',
      createSafeLogData({
        operation: 'CREATE_MANY',
        table: 'resource',
        count: Array.isArray(data) ? data.length : 1,
        data: data,
      }),
    );
    const result = await this.prisma.resource.createMany({
      data,
      skipDuplicates: true,
    });
    this.logger.info(
      '[Resource] Multiple resources created successfully',
      createSafeLogData({
        operation: 'CREATE_MANY',
        table: 'resource',
        count: result.count,
      }),
    );
    return result;
  }

  async findMany(
    resourceFindManyArgs: Prisma.ResourceFindManyArgs,
  ): Promise<{ itemCount: number; entities: Resource[] }> {
    const itemCount = await this.prisma.resource.count({
      where: resourceFindManyArgs.where,
    });
    const entities = await this.prisma.resource.findMany(resourceFindManyArgs);
    return { itemCount, entities };
  }

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

  async updateMany(resourceUpdateManyArgs: Prisma.ResourceUpdateManyArgs) {
    this.logger.info(
      '[Resource] Updating multiple resources',
      createSafeLogData({
        operation: 'UPDATE_MANY',
        table: 'resource',
        where: resourceUpdateManyArgs.where,
        data: resourceUpdateManyArgs.data,
      }),
    );
    const result = await this.prisma.resource.updateMany(
      resourceUpdateManyArgs,
    );
    this.logger.info(
      '[Resource] Multiple resources updated successfully',
      createSafeLogData({
        operation: 'UPDATE_MANY',
        table: 'resource',
        count: result.count,
      }),
    );
    return result;
  }

  async updateUnique(id: number, data: Prisma.ResourceUpdateManyArgs['data']) {
    const oldData = await this.prisma.resource.findUnique({ where: { id } });
    this.logger.info(
      '[Resource] Updating resource',
      createSafeLogData({
        operation: 'UPDATE',
        table: 'resource',
        id: id,
        oldData: oldData,
        newData: data,
      }),
    );
    const result = await this.prisma.resource.update({
      where: { id: id },
      data,
    });
    this.logger.info(
      '[Resource] Resource updated successfully',
      createSafeLogData({
        operation: 'UPDATE',
        table: 'resource',
        id: id,
        result: result,
      }),
    );
    return result;
  }

  async deleteMany(resourceDeleteManyArgs: Prisma.ResourceDeleteManyArgs) {
    const oldData = await this.prisma.resource.findMany({
      where: resourceDeleteManyArgs.where,
    });
    this.logger.info(
      '[Resource] Deleting multiple resources',
      createSafeLogData({
        operation: 'DELETE_MANY',
        table: 'resource',
        where: resourceDeleteManyArgs.where,
        oldData: oldData,
      }),
    );
    const result = await this.prisma.resource.deleteMany(
      resourceDeleteManyArgs,
    );
    this.logger.info(
      '[Resource] Multiple resources deleted successfully',
      createSafeLogData({
        operation: 'DELETE_MANY',
        table: 'resource',
        count: result.count,
      }),
    );
    return result;
  }

  async deleteUnique(id: number) {
    const oldData = await this.prisma.resource.findUnique({ where: { id } });
    this.logger.info(
      '[Resource] Deleting resource',
      createSafeLogData({
        operation: 'DELETE',
        table: 'resource',
        id: id,
        oldData: oldData,
      }),
    );
    await this.prisma.resource.delete({
      where: { id: id },
    });
    this.logger.info(
      '[Resource] Resource deleted successfully',
      createSafeLogData({
        operation: 'DELETE',
        table: 'resource',
        id: id,
      }),
    );
    return { count: 1 };
  }

  async count(resourceCountArgs?: Prisma.ResourceCountArgs) {
    return await this.prisma.resource.count(resourceCountArgs);
  }

  async groupBy(resourceGroupByArgs: Prisma.ResourceGroupByArgs) {
    return await this.prisma.resource.groupBy(resourceGroupByArgs as any);
  }

  async aggregate(resourceAggregateArgs: Prisma.ResourceAggregateArgs) {
    return await this.prisma.resource.aggregate(resourceAggregateArgs);
  }
}
