import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { AuditAction, AuditStatus, RiskLevel } from '@prisma/client';
import { getUsernameById, isAfterHours } from '../utils/audit-helpers';

/**
 * 合规报表服务
 * 生成 SOX、GDPR 等合规审计报表
 */
@Injectable()
export class ComplianceReportService {
  private readonly logger = new Logger(ComplianceReportService.name);

  constructor(private readonly prisma: PrismaService) {}

  /**
   * 生成 SOX 合规报表
   * @param region 区域
   * @param tenantId 租户ID
   * @param startDate 开始日期
   * @param endDate 结束日期
   */
  async generateSoxReport(
    region: string,
    tenantId: string,
    startDate: Date,
    endDate: Date,
  ) {
    this.logger.log(`Generating SOX compliance report for ${region}/${tenantId}`);

    const baseWhere = {
      region,
      tenantId,
      when: { gte: startDate, lte: endDate },
    };

    // 1. 财务操作汇总
    const financialSummary = await this.getFinancialOperationsSummary(
      baseWhere,
    );

    // 2. 权限变更记录
    const accessControlChanges = await this.getAccessControlChanges(baseWhere);

    // 3. 高风险操作
    const highRiskOperations = await this.getHighRiskOperations(baseWhere);

    // 4. 失败操作分析
    const failedOperations = await this.getFailedOperations(baseWhere);

    // 5. 完整性验证记录
    const integrityChecks = await this.getIntegrityCheckResults(
      region,
      tenantId,
      startDate,
      endDate,
    );

    // 6. 异常模式检测
    const anomalies = await this.detectAnomalies(baseWhere);

    return {
      reportType: 'SOX_COMPLIANCE',
      reportPeriod: {
        start: startDate.toISOString(),
        end: endDate.toISOString(),
      },
      generatedAt: new Date().toISOString(),
      region,
      tenantId,
      
      // 主要内容
      sections: {
        financialOperations: financialSummary,
        accessControlChanges,
        highRiskOperations,
        failedOperations,
        integrityChecks,
        anomalies,
      },

      // 合规状态评估
      complianceStatus: this.evaluateComplianceStatus({
        financialSummary,
        integrityChecks,
        highRiskOperations,
        failedOperations,
      }),
    };
  }

  /**
   * 1. 财务操作汇总
   */
  private async getFinancialOperationsSummary(baseWhere: any) {
    const financialWhere = { ...baseWhere, isFinancial: true };

    const [total, byAction, byUser, avgAmount] = await Promise.all([
      this.prisma.auditLog.count({ where: financialWhere }),
      this.prisma.auditLog.groupBy({
        by: ['action'],
        where: financialWhere,
        _count: true,
      }),
      this.prisma.auditLog.groupBy({
        by: ['userId'],
        where: financialWhere,
        _count: true,
      }),
      // 可以从 changes 中提取金额统计（如果有）
      this.prisma.auditLog.findMany({
        where: financialWhere,
        select: {
          action: true,
          changes: true,
        },
      }),
    ]);

    // 按操作类型统计
    const operationsByType = byAction.map((item) => ({
      action: item.action,
      count: item._count,
    }));

    // 获取活跃财务操作用户
    const topUsers = await Promise.all(
      byUser
        .sort((a, b) => b._count - a._count)
        .slice(0, 10)
        .map(async (item) => {
          const u = await getUsernameById(this.prisma, item.userId);
          return {
            userId: item.userId || 'anonymous',
            username: u.username,
            displayName: u.displayName,
            operationCount: item._count,
          };
        }),
    );

    return {
      totalOperations: total,
      operationsByType,
      topUsers,
      retentionCompliance: {
        required: '7 years',
        status: 'COMPLIANT',
      },
    };
  }

  /**
   * 2. 权限变更记录
   */
  private async getAccessControlChanges(baseWhere: any) {
    const accessChanges = await this.prisma.auditLog.findMany({
      where: {
        ...baseWhere,
        action: {
          in: [
            AuditAction.ROLE_CHANGE,
            AuditAction.PERMISSION_CHANGE,
          ],
        },
      },
      include: {
        user: {
          select: {
            username: true,
            displayName: true,
          },
        },
      },
      orderBy: { when: 'desc' },
    });

    // 统计变更类型
    const changesByType = {
      roleAssignments: accessChanges.filter(
        (log) => log.action === AuditAction.ROLE_CHANGE,
      ).length,
      permissionChanges: accessChanges.filter(
        (log) => log.action === AuditAction.PERMISSION_CHANGE,
      ).length,
    };

    return {
      totalChanges: accessChanges.length,
      changesByType,
      recentChanges: accessChanges.slice(0, 20).map((log) => ({
        id: log.id,
        when: log.when.toISOString(),
        who: log.user?.username || log.who,
        action: log.action,
        entityType: log.entityType,
        entityId: log.entityId,
        what: log.what,
        riskLevel: log.riskLevel,
      })),
    };
  }

  /**
   * 3. 高风险操作统计
   */
  private async getHighRiskOperations(baseWhere: any) {
    const highRiskLogs = await this.prisma.auditLog.findMany({
      where: {
        ...baseWhere,
        riskLevel: RiskLevel.HIGH,
      },
      include: {
        user: {
          select: {
            username: true,
            displayName: true,
          },
        },
      },
      orderBy: { when: 'desc' },
      take: 100,
    });

    // 按模块分类
    const byModule = highRiskLogs.reduce((acc, log) => {
      acc[log.module] = (acc[log.module] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    // 按操作类型分类
    const byAction = highRiskLogs.reduce((acc, log) => {
      acc[log.action] = (acc[log.action] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    return {
      totalHighRisk: highRiskLogs.length,
      byModule,
      byAction,
      recentOperations: highRiskLogs.slice(0, 20).map((log) => ({
        id: log.id,
        when: log.when.toISOString(),
        who: log.user?.username || log.who,
        module: log.module,
        action: log.action,
        what: log.what,
        status: log.status,
        isSensitive: log.isSensitive,
      })),
    };
  }

  /**
   * 4. 失败操作分析
   */
  private async getFailedOperations(baseWhere: any) {
    const failedLogs = await this.prisma.auditLog.findMany({
      where: {
        ...baseWhere,
        status: AuditStatus.FAILED,
      },
      include: {
        user: {
          select: {
            username: true,
            displayName: true,
          },
        },
      },
      orderBy: { when: 'desc' },
    });

    // 按错误类型分类
    const errorPatterns = failedLogs.reduce((acc, log) => {
      const errorType = this.categorizeError(log.errorMessage);
      acc[errorType] = (acc[errorType] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    // 失败率最高的模块
    const moduleFailures = failedLogs.reduce((acc, log) => {
      acc[log.module] = (acc[log.module] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    return {
      totalFailed: failedLogs.length,
      errorPatterns,
      moduleFailures,
      recentFailures: failedLogs.slice(0, 20).map((log) => ({
        id: log.id,
        when: log.when.toISOString(),
        who: log.user?.username || log.who,
        module: log.module,
        action: log.action,
        what: log.what,
        errorMessage: log.errorMessage,
      })),
    };
  }

  /**
   * 5. 完整性验证记录
   */
  private async getIntegrityCheckResults(
    region: string,
    tenantId: string,
    startDate: Date,
    endDate: Date,
  ) {
    const checks = await this.prisma.auditIntegrityCheckLog.findMany({
      where: {
        region,
        tenantId,
        createdAt: { gte: startDate, lte: endDate },
      },
      orderBy: { createdAt: 'desc' },
      take: 50,
    });

    const totalChecks = checks.length;
    const passedChecks = checks.filter((c) => c.status === 'SUCCESS').length;
    const failedChecks = checks.filter((c) => c.status === 'FAILED').length;

    return {
      totalChecks,
      passedChecks,
      failedChecks,
      passRate:
        totalChecks > 0
          ? Math.round((passedChecks / totalChecks) * 100 * 10) / 10
          : 100,
      recentChecks: checks.slice(0, 10).map((check) => ({
        id: check.id,
        checkType: check.checkType,
        when: check.createdAt.toISOString(),
        recordCount: check.recordCount,
        passCount: check.passCount,
        failCount: check.failCount,
        status: check.status,
      })),
      failures:
        failedChecks > 0
          ? checks
              .filter((c) => c.status === 'FAILED')
              .map((check) => ({
                id: check.id,
                when: check.createdAt.toISOString(),
                failCount: check.failCount,
                errorMessage: check.errorMessage,
                failures: check.failures,
              }))
          : [],
    };
  }

  /**
   * 6. 异常模式检测
   */
  private async detectAnomalies(baseWhere: any) {
    // 检测异常登录（多次失败）
    const loginFailures = await this.detectLoginAnomalies(baseWhere);

    // 检测批量操作（大量删除/修改）
    const bulkOperations = await this.detectBulkOperationAnomalies(baseWhere);

    // 检测非工作时间操作
    const afterHoursOps = await this.detectAfterHoursOperations(baseWhere);

    return {
      loginFailures,
      bulkOperations,
      afterHoursOps,
    };
  }

  /**
   * 检测登录异常
   */
  private async detectLoginAnomalies(baseWhere: any) {
    const loginFails = await this.prisma.auditLog.groupBy({
      by: ['userId'],
      where: {
        ...baseWhere,
        action: AuditAction.LOGIN_FAILED,
      },
      _count: true,
      having: {
        userId: {
          _count: {
            gt: 5, // 失败超过5次
          },
        },
      },
    });

    const anomalies = await Promise.all(
      loginFails.map(async (item) => {
        const u = await getUsernameById(this.prisma, item.userId);
        return {
          userId: item.userId || 'anonymous',
          username: u.username,
          failureCount: item._count,
          severity: item._count > 10 ? 'HIGH' : 'MEDIUM',
        };
      }),
    );

    return {
      detected: anomalies.length,
      anomalies,
    };
  }

  /**
   * 检测批量操作异常
   */
  private async detectBulkOperationAnomalies(baseWhere: any) {
    const bulkOps = await this.prisma.auditLog.findMany({
      where: {
        ...baseWhere,
        action: {
          in: [AuditAction.BULK_UPDATE, AuditAction.BULK_DELETE],
        },
      },
      include: {
        user: {
          select: {
            username: true,
            displayName: true,
          },
        },
      },
      orderBy: { when: 'desc' },
    });

    return {
      detected: bulkOps.length,
      operations: bulkOps.map((log) => ({
        id: log.id,
        when: log.when.toISOString(),
        who: log.user?.username || log.who,
        action: log.action,
        module: log.module,
        entityType: log.entityType,
        what: log.what,
        status: log.status,
      })),
    };
  }

  /**
   * 检测非工作时间操作
   */
  private async detectAfterHoursOperations(baseWhere: any) {
    // 查询所有敏感或高风险操作
    const sensitiveOps = await this.prisma.auditLog.findMany({
      where: {
        ...baseWhere,
        OR: [
          { isSensitive: true },
          { riskLevel: RiskLevel.HIGH },
        ],
      },
      include: {
        user: {
          select: {
            username: true,
            displayName: true,
          },
        },
      },
    });

    // 过滤非工作时间操作（18:00 - 08:00，周末）
    const afterHours = sensitiveOps.filter((log) => isAfterHours(log.when));

    return {
      detected: afterHours.length,
      operations: afterHours.slice(0, 50).map((log) => ({
        id: log.id,
        when: log.when.toISOString(),
        who: log.user?.username || log.who,
        module: log.module,
        action: log.action,
        what: log.what,
        riskLevel: log.riskLevel,
        isSensitive: log.isSensitive,
      })),
    };
  }

  /**
   * 评估合规状态
   */
  private evaluateComplianceStatus(data: {
    financialSummary: any;
    integrityChecks: any;
    highRiskOperations: any;
    failedOperations: any;
  }) {
    const issues: Array<{ severity: string; message: string }> = [];

    // 检查完整性验证
    if (data.integrityChecks.failedChecks > 0) {
      issues.push({
        severity: 'CRITICAL',
        message: `检测到 ${data.integrityChecks.failedChecks} 次完整性验证失败`,
      });
    }

    // 检查财务操作合规性
    if (data.financialSummary.totalOperations === 0) {
      issues.push({
        severity: 'WARNING',
        message: '期间内无财务操作记录',
      });
    }

    // 检查失败操作比例
    const failureRate = data.failedOperations.totalFailed;
    if (failureRate > 100) {
      issues.push({
        severity: 'WARNING',
        message: `检测到 ${failureRate} 次失败操作`,
      });
    }

    // 检查高风险操作
    if (data.highRiskOperations.totalHighRisk > 50) {
      issues.push({
        severity: 'INFO',
        message: `期间内有 ${data.highRiskOperations.totalHighRisk} 次高风险操作`,
      });
    }

    const status =
      issues.some((i) => i.severity === 'CRITICAL')
        ? 'NON_COMPLIANT'
        : issues.some((i) => i.severity === 'WARNING')
        ? 'REVIEW_REQUIRED'
        : 'COMPLIANT';

    return {
      status,
      issues,
      summary:
        status === 'COMPLIANT'
          ? '审计日志符合 SOX 合规要求'
          : status === 'REVIEW_REQUIRED'
          ? '审计日志需要人工审查'
          : '检测到严重合规问题，需要立即处理',
    };
  }

  /**
   * 生成 GDPR 数据访问报告
   * @param userId 用户ID（数据主体）
   * @param region 区域
   * @param tenantId 租户ID
   */
  async generateGdprDataAccessReport(
    userId: string,
    region: string,
    tenantId: string,
  ) {
    this.logger.log(`Generating GDPR data access report for user ${userId}`);

    // 查询所有访问该用户数据的操作
    const accessLogs = await this.prisma.auditLog.findMany({
      where: {
        region,
        tenantId,
        OR: [
          { userId }, // 用户自己的操作
          { entityId: userId }, // 其他人对该用户的操作
        ],
      },
      include: {
        user: {
          select: {
            username: true,
            displayName: true,
          },
        },
      },
      orderBy: { when: 'desc' },
    });

    // 按操作类型分类
    const accessByAction = accessLogs.reduce((acc, log) => {
      acc[log.action] = (acc[log.action] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    // 获取访问该用户数据的其他用户
    const accessors = Array.from(
      new Set(
        accessLogs
          .filter((log) => log.userId !== userId && log.entityId === userId)
          .map((log) => log.userId),
      ),
    );

    const accessorDetails = await Promise.all(
      accessors.map(async (accessorId) => {
        const u = await getUsernameById(this.prisma, accessorId);
        const count = accessLogs.filter((log) => log.userId === accessorId).length;
        return {
          userId: accessorId || 'anonymous',
          username: u.username,
          accessCount: count,
        };
      }),
    );

    return {
      reportType: 'GDPR_DATA_ACCESS',
      generatedAt: new Date().toISOString(),
      dataSubject: {
        userId,
      },
      summary: {
        totalAccesses: accessLogs.length,
        accessByAction,
        uniqueAccessors: accessors.length,
      },
      accessors: accessorDetails,
      recentAccesses: accessLogs.slice(0, 50).map((log) => ({
        when: log.when.toISOString(),
        who: log.user?.username || log.who,
        action: log.action,
        module: log.module,
        what: log.what,
      })),
    };
  }

  /**
   * 生成异常报告
   */
  async generateAnomalyReport(
    region: string,
    tenantId: string,
    startDate: Date,
    endDate: Date,
  ) {
    const baseWhere = {
      region,
      tenantId,
      when: { gte: startDate, lte: endDate },
    };

    const anomalies = await this.detectAnomalies(baseWhere);

    return {
      reportType: 'ANOMALY_DETECTION',
      reportPeriod: {
        start: startDate.toISOString(),
        end: endDate.toISOString(),
      },
      generatedAt: new Date().toISOString(),
      region,
      tenantId,
      anomalies,
      severity: this.calculateAnomalySeverity(anomalies),
    };
  }

  /**
   * 计算异常严重程度
   */
  private calculateAnomalySeverity(anomalies: any) {
    const criticalCount =
      (anomalies.loginFailures.anomalies?.filter((a: any) => a.severity === 'HIGH')
        .length || 0) + anomalies.bulkOperations.detected;

    if (criticalCount > 10) return 'CRITICAL';
    if (criticalCount > 5) return 'HIGH';
    if (criticalCount > 0) return 'MEDIUM';
    return 'LOW';
  }

  /**
   * 错误分类
   */
  private categorizeError(errorMessage: string | null): string {
    if (!errorMessage) return 'UNKNOWN';

    const lowerMsg = errorMessage.toLowerCase();

    if (lowerMsg.includes('permission') || lowerMsg.includes('forbidden')) {
      return 'PERMISSION_DENIED';
    }
    if (lowerMsg.includes('not found')) {
      return 'RESOURCE_NOT_FOUND';
    }
    if (lowerMsg.includes('validation') || lowerMsg.includes('invalid')) {
      return 'VALIDATION_ERROR';
    }
    if (lowerMsg.includes('timeout')) {
      return 'TIMEOUT';
    }
    if (lowerMsg.includes('database') || lowerMsg.includes('connection')) {
      return 'DATABASE_ERROR';
    }

    return 'OTHER';
  }

  /**
   * 导出报表为 CSV 格式
   */
  async exportReportToCsv(report: any): Promise<string> {
    // 简单的CSV导出，实际可以使用专门的CSV库
    const lines: string[] = [];

    // 标题
    lines.push('# SOX Compliance Report');
    lines.push(`# Generated: ${report.generatedAt}`);
    lines.push(`# Period: ${report.reportPeriod.start} to ${report.reportPeriod.end}`);
    lines.push(`# Region: ${report.region}, Tenant: ${report.tenantId}`);
    lines.push('');

    // 财务操作汇总
    lines.push('## Financial Operations Summary');
    lines.push('Action,Count');
    report.sections.financialOperations.operationsByType.forEach((op: any) => {
      lines.push(`${op.action},${op.count}`);
    });
    lines.push('');

    // 合规状态
    lines.push('## Compliance Status');
    lines.push(`Status,${report.complianceStatus.status}`);
    lines.push(`Summary,${report.complianceStatus.summary}`);
    lines.push('');

    return lines.join('\n');
  }
}
