import { Injectable, Inject, Logger, Optional } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { PrismaService } from './prisma.service';

@Injectable()
export class AuditService {
  private readonly logger = new Logger(AuditService.name);
  constructor(
    private prisma: PrismaService,
    @Optional() @Inject(REQUEST) private request?: any,
  ) {}

  async log(input: {
    userId?: string;
    action: 'CREATE' | 'UPDATE' | 'DELETE' | 'LOGIN' | 'LOGOUT' | 'VERIFY' | string;
    entityType: string;
    entityId?: string;
    oldData?: any;
    newData?: any;
  }) {
    try {
      const ipAddress = this.getIpAddress();
      const userAgent = this.getUserAgent();

      await this.prisma.auditLog.create({
        data: {
          iamUserId: input.userId,
          action: input.action,
          entityType: input.entityType,
          entityId: input.entityId,
          oldData: input.oldData,
          newData: input.newData,
          ipAddress,
          userAgent,
        },
      });
    } catch (error) {
      this.logger.error('Failed to log audit event:', error);
      // Don't throw - audit logging should not break main operations
    }
  }

  private getIpAddress(): string {
    if (!this.request) return '';
    
    return (
      this.request.headers['x-forwarded-for']?.split(',')[0].trim() ||
      this.request.headers['x-real-ip'] ||
      this.request.connection?.remoteAddress ||
      this.request.socket?.remoteAddress ||
      this.request.ip ||
      ''
    );
  }

  private getUserAgent(): string {
    return this.request?.headers?.['user-agent'] || '';
  }

  async getLogs(filters: any = {}) {
    const where: any = {};

    if (filters.search) {
      where.OR = [
        { entityId: { contains: filters.search, mode: 'insensitive' } },
        { iamUserId: { contains: filters.search, mode: 'insensitive' } },
      ];
    }

    if (filters.action) {
      where.action = filters.action;
    }

    if (filters.entityType) {
      where.entityType = filters.entityType;
    }

    const limit = Math.min(filters.limit ?? 50, 200);
    const offset = filters.offset ?? 0;

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

    return { data, total, limit, offset };
  }

  async getLog(id: string) {
    return this.prisma.auditLog.findUnique({ where: { id } });
  }
}
