import { PrismaClient } from '@prisma/client';

import { getPrismaClient } from '../../../config/database.config';
import { AccessSummaryFiltersDto, UserActivityFiltersDto, SecurityEventsFiltersDto } from '../governance.dto';

/**
 * EN: Reporting Service
 * VI: Service báo cáo
 */
export class ReportingService {
  private prisma: PrismaClient;

  constructor() {
    this.prisma = getPrismaClient();
  }

  /**
   * EN: Get access summary
   * VI: Lấy tổng quan truy cập
   */
  async getAccessSummary(filters: AccessSummaryFiltersDto): Promise<any> {
    const dateFilter: any = {};

    if (filters.periodStart || filters.periodEnd) {
      dateFilter.gte = filters.periodStart ? new Date(filters.periodStart) : undefined;
      dateFilter.lte = filters.periodEnd ? new Date(filters.periodEnd) : undefined;
    }

    const [
      totalUsers,
      activeUsers,
      totalRoles,
      totalPermissions,
      accessRequests,
    ] = await Promise.all([
      this.prisma.user.count({ where: filters.organizationId ? { organizationId: filters.organizationId } : {} }),
      this.prisma.user.count({
        where: {
          isActive: true,
          ...(filters.organizationId && { organizationId: filters.organizationId }),
          ...(Object.keys(dateFilter).length > 0 && {
            lastLoginAt: dateFilter,
          }),
        },
      }),
      this.prisma.role.count(),
      this.prisma.permission.count(),
      this.prisma.accessRequest.count({
        where: Object.keys(dateFilter).length > 0 ? { requestedAt: dateFilter } : {},
      }),
    ]);

    return {
      users: {
        total: totalUsers,
        active: activeUsers,
        inactive: totalUsers - activeUsers,
      },
      accessControl: {
        roles: totalRoles,
        permissions: totalPermissions,
        accessRequests,
      },
      period: {
        start: filters.periodStart,
        end: filters.periodEnd,
      },
    };
  }

  /**
   * EN: Get user activity
   * VI: Lấy hoạt động của user
   */
  async getUserActivity(filters: UserActivityFiltersDto): Promise<any> {
    const where: any = { userId: filters.userId };

    if (filters.periodStart || filters.periodEnd) {
      where.timestamp = {};
      if (filters.periodStart) where.timestamp.gte = new Date(filters.periodStart);
      if (filters.periodEnd) where.timestamp.lte = new Date(filters.periodEnd);
    }

    if (filters.eventType) {
      where.eventType = filters.eventType;
    }

    const events = await this.prisma.authEvent.findMany({
      where,
      orderBy: { timestamp: 'desc' },
      take: 100,
    });

    const user = await this.prisma.user.findUnique({
      where: { id: filters.userId },
      select: {
        id: true,
        email: true,
        username: true,
        lastLoginAt: true,
        loginCount: true,
      },
    });

    return {
      user,
      events,
      totalEvents: events.length,
      period: {
        start: filters.periodStart,
        end: filters.periodEnd,
      },
    };
  }

  /**
   * EN: Get security events
   * VI: Lấy các sự kiện bảo mật
   */
  async getSecurityEvents(filters: SecurityEventsFiltersDto): Promise<{ events: any[]; total: number }> {
    const where: any = {};

    if (filters.periodStart || filters.periodEnd) {
      where.timestamp = {};
      if (filters.periodStart) where.timestamp.gte = new Date(filters.periodStart);
      if (filters.periodEnd) where.timestamp.lte = new Date(filters.periodEnd);
    }

    if (filters.eventType) {
      where.eventType = filters.eventType;
    }

    if (filters.success !== undefined) {
      where.success = filters.success;
    }

    // Focus on security-related events
    where.eventType = {
      in: [
        'LOGIN_FAILED',
        'UNAUTHORIZED_ACCESS',
        'TOKEN_REVOKED',
        'PASSWORD_CHANGED',
        'MFA_ENABLED',
        'MFA_DISABLED',
        'PERMISSION_CHANGED',
        'ROLE_ASSIGNED',
        'ROLE_REVOKED',
      ],
    };

    const [events, total] = await Promise.all([
      this.prisma.authEvent.findMany({
        where,
        skip: filters.skip,
        take: filters.take,
        orderBy: { timestamp: 'desc' },
        include: {
          user: {
            select: {
              id: true,
              email: true,
              username: true,
            },
          },
        },
      }),
      this.prisma.authEvent.count({ where }),
    ]);

    return { events, total };
  }

  /**
   * EN: Get compliance status
   * VI: Lấy trạng thái tuân thủ
   */
  async getComplianceStatus(): Promise<any> {
    const [
      totalReports,
      publishedReports,
      pendingReviews,
      completedReviews,
    ] = await Promise.all([
      this.prisma.complianceReport.count(),
      this.prisma.complianceReport.count({ where: { status: 'PUBLISHED' } }),
      this.prisma.accessReview.count({ where: { status: 'ACTIVE' } }),
      this.prisma.accessReview.count({ where: { status: 'COMPLETED' } }),
    ]);

    return {
      reports: {
        total: totalReports,
        published: publishedReports,
      },
      reviews: {
        pending: pendingReviews,
        completed: completedReviews,
      },
      lastUpdated: new Date(),
    };
  }

  /**
   * EN: Get risk overview
   * VI: Lấy tổng quan rủi ro
   */
  async getRiskOverview(): Promise<any> {
    const scores = await this.prisma.riskScore.findMany({
      orderBy: { calculatedAt: 'desc' },
      take: 1000,
      include: {
        user: {
          select: {
            id: true,
            email: true,
            username: true,
          },
        },
      },
    });

    const distribution = {
      LOW: scores.filter((s) => s.level === 'LOW').length,
      MEDIUM: scores.filter((s) => s.level === 'MEDIUM').length,
      HIGH: scores.filter((s) => s.level === 'HIGH').length,
      CRITICAL: scores.filter((s) => s.level === 'CRITICAL').length,
    };

    const averageScore = scores.length > 0
      ? scores.reduce((sum, s) => sum + s.score, 0) / scores.length
      : 0;

    const highRiskUsers = scores
      .filter((s) => s.level === 'HIGH' || s.level === 'CRITICAL')
      .slice(0, 10);

    return {
      distribution,
      averageScore: Math.round(averageScore * 100) / 100,
      totalScored: scores.length,
      highRiskUsers: highRiskUsers.map((s) => ({
        user: s.user,
        score: s.score,
        level: s.level,
      })),
    };
  }
}

export const reportingService = new ReportingService();
