import { Injectable } from '@nestjs/common';
import { type AdminAction, type AuditTargetType, type Prisma } from '@prisma/client';
import { PrismaService } from '@modules/shared';
import {
  type IAuditLogRepository,
  type AuditLogEntry,
  type AuditLogListResult,
  type CreateAuditLogInput,
} from '../../domain/repositories/audit-log.repository';

@Injectable()
export class PrismaAuditLogRepository implements IAuditLogRepository {
  constructor(private readonly prisma: PrismaService) {}

  async create(input: CreateAuditLogInput): Promise<AuditLogEntry> {
    const record = await this.prisma.adminAuditLog.create({
      data: {
        action: input.action as AdminAction,
        actorId: input.actorId,
        targetId: input.targetId,
        targetType: input.targetType as AuditTargetType,
        metadata: input.metadata as Prisma.InputJsonValue ?? undefined,
      },
    });

    return {
      id: record.id,
      action: record.action,
      actorId: record.actorId,
      targetId: record.targetId,
      targetType: record.targetType,
      metadata: record.metadata as Record<string, unknown> | null,
      ipAddress: record.ipAddress,
      userAgent: record.userAgent,
      createdAt: record.createdAt,
    };
  }

  async findAll(params: {
    page: number;
    limit: number;
    action?: string;
    actorId?: string;
    targetId?: string;
    targetType?: string;
    startDate?: Date;
    endDate?: Date;
  }): Promise<AuditLogListResult> {
    const { page, limit, action, actorId, targetId, targetType, startDate, endDate } = params;
    const skip = (page - 1) * limit;

    const where: Prisma.AdminAuditLogWhereInput = {};

    if (action) {
      where.action = action as AdminAction;
    }
    if (actorId) {
      where.actorId = actorId;
    }
    if (targetId) {
      where.targetId = targetId;
    }
    if (targetType) {
      where.targetType = targetType as AuditTargetType;
    }
    if (startDate || endDate) {
      where.createdAt = {};
      if (startDate) {
        where.createdAt.gte = startDate;
      }
      if (endDate) {
        where.createdAt.lte = endDate;
      }
    }

    const [records, total] = await Promise.all([
      this.prisma.adminAuditLog.findMany({
        where,
        orderBy: { createdAt: 'desc' },
        skip,
        take: limit,
      }),
      this.prisma.adminAuditLog.count({ where }),
    ]);

    return {
      data: records.map((r) => ({
        id: r.id,
        action: r.action,
        actorId: r.actorId,
        targetId: r.targetId,
        targetType: r.targetType,
        metadata: r.metadata as Record<string, unknown> | null,
        ipAddress: r.ipAddress,
        userAgent: r.userAgent,
        createdAt: r.createdAt,
      })),
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }
}
