import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Between, Like } from 'typeorm';
import { AuditLog } from './entities/audit-log.entity';

export interface AuditFilters {
  user_id?: number;
  entity_type?: string;
  action?: string;
  start_date?: string;
  end_date?: string;
  page?: number;
  limit?: number;
}

@Injectable()
export class AuditService {
  constructor(
    @InjectRepository(AuditLog)
    private readonly auditLogRepo: Repository<AuditLog>,
  ) {}

  // ─── Lister les logs avec filtres et pagination ──────────────────────────────
  async findAll(filters: AuditFilters): Promise<{
    data: AuditLog[];
    total: number;
    page: number;
    limit: number;
  }> {
    const page  = filters.page  ?? 1;
    const limit = filters.limit ?? 20;

    const query = this.auditLogRepo
      .createQueryBuilder('log')
      .leftJoinAndSelect('log.user', 'user')
      .orderBy('log.created_at', 'DESC');

    if (filters.user_id) {
      query.andWhere('user.id = :userId', { userId: filters.user_id });
    }

    if (filters.entity_type) {
      query.andWhere('log.entity_type = :entityType', {
        entityType: filters.entity_type,
      });
    }

    if (filters.action) {
      query.andWhere('log.action LIKE :action', {
        action: `%${filters.action}%`,
      });
    }

    if (filters.start_date && filters.end_date) {
      query.andWhere('log.created_at BETWEEN :start AND :end', {
        start: new Date(filters.start_date),
        end:   new Date(filters.end_date + 'T23:59:59'),
      });
    }

    const total = await query.getCount();
    const data  = await query
      .skip((page - 1) * limit)
      .take(limit)
      .getMany();

    return { data, total, page, limit };
  }

  // ─── Détail d'un log ─────────────────────────────────────────────────────────
  async findOne(id: number): Promise<AuditLog | null> {
    return this.auditLogRepo.findOne({
      where: { id },
      relations: ['user'],
    });
  }

  // ─── Logs d'une entité spécifique ────────────────────────────────────────────
  async findByEntity(
    entityType: string,
    entityId: number,
  ): Promise<AuditLog[]> {
    return this.auditLogRepo.find({
      where: { entity_type: entityType, entity_id: entityId },
      relations: ['user'],
      order: { created_at: 'DESC' },
    });
  }

  // ─── Créer un log manuellement ───────────────────────────────────────────────
  async create(data: Partial<AuditLog>): Promise<AuditLog> {
    return this.auditLogRepo.save(this.auditLogRepo.create(data));
  }

  // ─── Actions disponibles (pour les filtres) ──────────────────────────────────
  async getAvailableActions(): Promise<string[]> {
    const logs = await this.auditLogRepo
      .createQueryBuilder('log')
      .select('DISTINCT log.action', 'action')
      .getRawMany();

    return logs.map(l => l.action);
  }

  // ─── Types d'entités disponibles (pour les filtres) ──────────────────────────
  async getAvailableEntityTypes(): Promise<string[]> {
    const logs = await this.auditLogRepo
      .createQueryBuilder('log')
      .select('DISTINCT log.entity_type', 'entity_type')
      .getRawMany();

    return logs.map(l => l.entity_type);
  }

  // ─── Stats résumé ────────────────────────────────────────────────────────────
  async getStats(): Promise<{
    total: number;
    by_action: { action: string; count: number }[];
    by_entity: { entity_type: string; count: number }[];
    recent: AuditLog[];
  }> {
    const total = await this.auditLogRepo.count();

    const by_action = await this.auditLogRepo
      .createQueryBuilder('log')
      .select('log.action', 'action')
      .addSelect('COUNT(*)', 'count')
      .groupBy('log.action')
      .orderBy('count', 'DESC')
      .getRawMany();

    const by_entity = await this.auditLogRepo
      .createQueryBuilder('log')
      .select('log.entity_type', 'entity_type')
      .addSelect('COUNT(*)', 'count')
      .groupBy('log.entity_type')
      .orderBy('count', 'DESC')
      .getRawMany();

    const recent = await this.auditLogRepo.find({
      relations: ['user'],
      order: { created_at: 'DESC' },
      take: 10,
    });

    return { total, by_action, by_entity, recent };
  }

  // ─── Export CSV journal d'audit ──────────────────────────────────────────────
  async exportCSV(filters: AuditFilters): Promise<string> {
    const query = this.auditLogRepo
      .createQueryBuilder('log')
      .leftJoinAndSelect('log.user', 'user')
      .orderBy('log.created_at', 'DESC');

    if (filters.user_id)    query.andWhere('user.id = :userId', { userId: filters.user_id });
    if (filters.entity_type) query.andWhere('log.entity_type = :entityType', { entityType: filters.entity_type });
    if (filters.action)     query.andWhere('log.action LIKE :action', { action: `%${filters.action}%` });
    if (filters.start_date && filters.end_date) {
      query.andWhere('log.created_at BETWEEN :start AND :end', {
        start: new Date(filters.start_date),
        end:   new Date(filters.end_date + 'T23:59:59'),
      });
    }

    const logs = await query.take(10000).getMany();

    const headers = ['ID', 'Date', 'Heure', 'Utilisateur', 'Email', 'Action', 'Entité', 'ID Entité', 'IP'];
    const rows = logs.map(log => [
      log.id,
      new Date(log.created_at).toLocaleDateString('fr-FR'),
      new Date(log.created_at).toLocaleTimeString('fr-FR'),
      log.user ? `${log.user.last_name} ${log.user.first_name}` : 'Système',
      log.user?.email ?? '',
      log.action,
      log.entity_type,
      log.entity_id,
      log.ip_address ?? '',
    ]);

    const csv = [headers, ...rows].map(row => row.join(',')).join('\\n');
    return '\\uFEFF' + csv; // BOM UTF-8
  }
}