import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ClsService } from 'nestjs-cls';
import { AuditLogEntity } from '../../../entities/audit-log.entity';
import { CLS_TENANT_ID, CLS_USER_ID } from '../../../common/cls/cls.constants';

@Injectable()
export class AuditRepository {
  constructor(
    @InjectRepository(AuditLogEntity)
    private readonly repo: Repository<AuditLogEntity>,
    private readonly cls: ClsService,
  ) {}

  private getTenantId(): string {
    const tenantId = this.cls.get<string>(CLS_TENANT_ID);
    if (!tenantId) {
      throw new Error('AuditRepository: tenant_id not found in CLS context.');
    }
    return tenantId;
  }

  private getUserId(): string | null {
    return this.cls.get<string>(CLS_USER_ID) || null;
  }

  async log(
    entityType: string,
    entityId: string,
    action: string,
    changes?: { field: string; old_value: any; new_value: any }[] | null,
  ): Promise<AuditLogEntity> {
    return this.repo.save({
      tenant_id: this.getTenantId(),
      entity_type: entityType,
      entity_id: entityId,
      action,
      changes: changes || null,
      performed_by: this.getUserId(),
    });
  }

  async findRecent(limit = 10): Promise<AuditLogEntity[]> {
    return this.repo.find({
      where: { tenant_id: this.getTenantId() },
      relations: ['performer'],
      order: { created_at: 'DESC' },
      take: limit,
    });
  }

  async findByEntity(
    entityType: string,
    entityId: string,
    options?: { page?: number; limit?: number },
  ): Promise<{ items: AuditLogEntity[]; meta: { total: number; page: number; limit: number; totalPages: number } }> {
    const page = options?.page || 1;
    const limit = options?.limit || 50;
    const skip = (page - 1) * limit;

    const [items, total] = await this.repo.findAndCount({
      where: {
        tenant_id: this.getTenantId(),
        entity_type: entityType,
        entity_id: entityId,
      },
      relations: ['performer'],
      order: { created_at: 'DESC' },
      skip,
      take: limit,
    });

    return {
      items,
      meta: {
        total,
        page,
        limit,
        totalPages: Math.ceil(total / limit),
      },
    };
  }
}
