/**
 * Audit Service
 *
 * Provides centralized audit logging functionality
 * Tracks all important actions for security and compliance
 */

import { Injectable, Logger, Inject } from '@nestjs/common';
import { v4 as uuidv4 } from 'uuid';
import { AuditLog, AuditAction, AuditStatus } from '@domain/entities/audit-log.entity';
import {
  AuditLogRepository,
  AUDIT_LOG_REPOSITORY,
  AuditLogFilters,
} from '@domain/ports/out/audit-log.repository';

export interface LogAuditInput {
  action: AuditAction;
  status: AuditStatus;
  userId: string;
  userEmail: string;
  organizationId: string;
  resourceType?: string;
  resourceId?: string;
  resourceName?: string;
  metadata?: Record<string, any>;
  ipAddress?: string;
  userAgent?: string;
  errorMessage?: string;
}

@Injectable()
export class AuditService {
  private readonly logger = new Logger(AuditService.name);

  constructor(
    @Inject(AUDIT_LOG_REPOSITORY)
    private readonly auditLogRepository: AuditLogRepository
  ) {}

  /**
   * Log an audit event
   */
  async log(input: LogAuditInput): Promise<void> {
    try {
      const auditLog = AuditLog.create({
        id: uuidv4(),
        ...input,
      });

      await this.auditLogRepository.save(auditLog);

      this.logger.log(`Audit log created: ${input.action} by ${input.userEmail} (${input.status})`);
    } catch (error: any) {
      // Never throw on audit logging failure - log the error and continue
      this.logger.error(
        `Failed to create audit log: ${error?.message || 'Unknown error'}`,
        error?.stack
      );
    }
  }

  /**
   * Log successful action
   */
  async logSuccess(
    action: AuditAction,
    userId: string,
    userEmail: string,
    organizationId: string,
    options?: {
      resourceType?: string;
      resourceId?: string;
      resourceName?: string;
      metadata?: Record<string, any>;
      ipAddress?: string;
      userAgent?: string;
    }
  ): Promise<void> {
    await this.log({
      action,
      status: AuditStatus.SUCCESS,
      userId,
      userEmail,
      organizationId,
      ...options,
    });
  }

  /**
   * Log failed action
   */
  async logFailure(
    action: AuditAction,
    userId: string,
    userEmail: string,
    organizationId: string,
    errorMessage: string,
    options?: {
      resourceType?: string;
      resourceId?: string;
      metadata?: Record<string, any>;
      ipAddress?: string;
      userAgent?: string;
    }
  ): Promise<void> {
    await this.log({
      action,
      status: AuditStatus.FAILURE,
      userId,
      userEmail,
      organizationId,
      errorMessage,
      ...options,
    });
  }

  /**
   * Get audit logs with filters
   */
  async getAuditLogs(filters: AuditLogFilters): Promise<{
    logs: AuditLog[];
    total: number;
  }> {
    const [logs, total] = await Promise.all([
      this.auditLogRepository.findByFilters(filters),
      this.auditLogRepository.count(filters),
    ]);

    return { logs, total };
  }

  /**
   * Get audit trail for a specific resource
   */
  async getResourceAuditTrail(resourceType: string, resourceId: string): Promise<AuditLog[]> {
    return this.auditLogRepository.findByResource(resourceType, resourceId);
  }

  /**
   * Get recent activity for an organization
   */
  async getOrganizationActivity(organizationId: string, limit: number = 50): Promise<AuditLog[]> {
    return this.auditLogRepository.findRecentByOrganization(organizationId, limit);
  }

  /**
   * Get user activity history
   */
  async getUserActivity(userId: string, limit: number = 50): Promise<AuditLog[]> {
    return this.auditLogRepository.findByUser(userId, limit);
  }
}
