import { Injectable } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { AuditLogRepository } from '../repositories/audit-log.repository';

@Injectable()
export class AuditLogsService {
  constructor(
    private readonly auditLogRepository: AuditLogRepository,
    private readonly prisma: PrismaService,
  ) {}

  async listAuditLogs(filters: {
    userId?: string;
    userEmail?: string;
    action?: string;
    resource?: string;
    startDate?: string;
    endDate?: string;
    page?: string;
    pageSize?: string;
  }) {
    const { startDate, endDate } = this.parseDateRange(filters.startDate, filters.endDate);
    const parsedFilters = {
      userId: filters.userId || undefined,
      userEmail: filters.userEmail || undefined,
      action: filters.action || undefined,
      resource: filters.resource || undefined,
      startDate,
      endDate,
      page: filters.page ? parseInt(filters.page, 10) : 1,
      pageSize: filters.pageSize ? parseInt(filters.pageSize, 10) : 50,
    };

    const [items, total] = await Promise.all([
      this.auditLogRepository.listAuditLogs(parsedFilters),
      this.auditLogRepository.countAuditLogs(parsedFilters),
    ]);

    return {
      logs: items,
      pagination: {
        page: parsedFilters.page,
        pageSize: parsedFilters.pageSize,
        total,
        totalPages: Math.ceil(total / parsedFilters.pageSize),
      },
    };
  }

  async getAuditLogStats(filters: { startDate?: string; endDate?: string; userId?: string }) {
    const { startDate, endDate } = this.parseDateRange(filters.startDate, filters.endDate);
    let days = 7;
    if (startDate && endDate) {
      const diffMs = endDate.getTime() - startDate.getTime();
      days = Math.max(1, Math.ceil(diffMs / (1000 * 60 * 60 * 24)) + 1);
    }

    const cutoffDate = startDate || (() => {
      const fallback = new Date();
      fallback.setDate(fallback.getDate() - days);
      return fallback;
    })();

    const [actionStats, resourceStats, userStats, sourceStats, errorCount] = await Promise.all([
      this.prisma.meetingAttendanceAuditLog.groupBy({
        by: ['action'],
        _count: { id: true },
        where: { createdAt: { gte: cutoffDate, ...(endDate ? { lte: endDate } : {}) } },
        orderBy: { _count: { id: 'desc' } },
        take: 10,
      }),
      this.prisma.meetingAttendanceAuditLog.groupBy({
        by: ['resource'],
        _count: { id: true },
        where: { createdAt: { gte: cutoffDate, ...(endDate ? { lte: endDate } : {}) } },
        orderBy: { _count: { id: 'desc' } },
      }),
      this.prisma.meetingAttendanceAuditLog.groupBy({
        by: ['userEmail'],
        _count: { id: true },
        where: { createdAt: { gte: cutoffDate, ...(endDate ? { lte: endDate } : {}) } },
        orderBy: { _count: { id: 'desc' } },
        take: 5,
      }),
      this.prisma.meetingAttendanceAuditLog.groupBy({
        by: ['source'],
        _count: { id: true },
        where: { createdAt: { gte: cutoffDate, ...(endDate ? { lte: endDate } : {}) } },
        orderBy: { _count: { id: 'desc' } },
      }),
      this.prisma.meetingAttendanceAuditLog.count({
        where: {
          createdAt: { gte: cutoffDate, ...(endDate ? { lte: endDate } : {}) },
          statusCode: { gte: 400 },
        },
      }),
    ]);

    return {
      actionStats: actionStats.map((stat) => ({ action: stat.action, count: stat._count.id })),
      resourceStats: resourceStats.map((stat) => ({ resource: stat.resource, count: stat._count.id })),
      userStats: userStats.map((stat) => ({ userEmail: stat.userEmail, count: stat._count.id })),
      sourceStats: sourceStats.map((stat) => ({ source: stat.source, count: stat._count.id })),
      errorCount,
      periodDays: days,
    };
  }

  private parseDateRange(start?: string, end?: string) {
    const startDate = this.parseDate(start, 'start');
    const endDate = this.parseDate(end, 'end');
    return { startDate, endDate };
  }

  private parseDate(value: string | undefined, mode: 'start' | 'end') {
    if (!value) return undefined;
    const trimmed = value.trim();
    const isDateOnly = /^\d{4}-\d{2}-\d{2}$/.test(trimmed);
    if (!isDateOnly) {
      const parsed = new Date(trimmed);
      return Number.isNaN(parsed.getTime()) ? undefined : parsed;
    }
    const [year, month, day] = trimmed.split('-').map(Number);
    if (!year || !month || !day) return undefined;
    if (mode === 'start') {
      return new Date(year, month - 1, day, 0, 0, 0, 0);
    }
    return new Date(year, month - 1, day, 23, 59, 59, 999);
  }
}
