import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { AmlAlert, AlertStatus } from '../../domain/entities/aml-alert.entity';
import { IAmlAlertRepository } from '../../domain/repositories/aml-alert.repository.interface';

@Injectable()
export class AmlAlertRepository implements IAmlAlertRepository {
  constructor(
    @InjectRepository(AmlAlert)
    private readonly repo: Repository<AmlAlert>,
  ) {}

  create(data: Partial<AmlAlert>): AmlAlert {
    return this.repo.create(data);
  }

  async save(alert: AmlAlert): Promise<AmlAlert> {
    return this.repo.save(alert);
  }

  async findById(id: string): Promise<AmlAlert | null> {
    return this.repo.findOne({ where: { id } });
  }

  async findAndCount(options: {
    where?: Record<string, any>;
    skip?: number;
    take?: number;
    order?: Record<string, 'ASC' | 'DESC'>;
  }): Promise<[AmlAlert[], number]> {
    return this.repo.findAndCount(options);
  }

  async find(options: {
    where?: Record<string, any> | Record<string, any>[];
    order?: Record<string, 'ASC' | 'DESC'>;
    take?: number;
  }): Promise<AmlAlert[]> {
    return this.repo.find(options);
  }

  async count(options?: { where?: Record<string, any> | Record<string, any>[] }): Promise<number> {
    return this.repo.count(options);
  }

  async update(id: string, data: Partial<AmlAlert>): Promise<void> {
    await this.repo.update(id, data);
  }

  async countHighRiskActive(threshold: number): Promise<number> {
    return this.repo
      .createQueryBuilder('a')
      .where('a.risk_score >= :threshold', { threshold })
      .andWhere('a.status != :resolved', { resolved: AlertStatus.RESOLVED })
      .andWhere('a.status != :dismissed', { dismissed: AlertStatus.DISMISSED })
      .getCount();
  }

  async findPaginated(
    page: number,
    limit: number,
    filters?: { status?: string; pattern?: string },
  ): Promise<[AmlAlert[], number]> {
    const qb = this.repo.createQueryBuilder('alert');

    if (filters?.status) {
      qb.andWhere('alert.status = :status', { status: filters.status });
    }
    if (filters?.pattern) {
      qb.andWhere('alert.pattern = :pattern', { pattern: filters.pattern });
    }

    qb.orderBy('alert.created_at', 'DESC')
      .skip((page - 1) * limit)
      .take(limit);

    return qb.getManyAndCount();
  }

  async findSuspicious(
    page: number,
    limit: number,
    threshold: number,
  ): Promise<[AmlAlert[], number]> {
    const qb = this.repo
      .createQueryBuilder('alert')
      .where('alert.risk_score >= :threshold', { threshold })
      .orderBy('alert.risk_score', 'DESC')
      .addOrderBy('alert.created_at', 'DESC')
      .skip((page - 1) * limit)
      .take(limit);

    return qb.getManyAndCount();
  }

  async countHighRisk(threshold: number): Promise<number> {
    return this.repo
      .createQueryBuilder('a')
      .where('a.risk_score >= :score', { score: threshold })
      .getCount();
  }
}
