/**
 * 管理员操作日志服务
 *
 * 功能描述：
 * - 记录管理员的所有数据库操作
 * - 提供操作日志的查询和统计功能
 * - 支持敏感操作的特殊标记
 * - 实现日志的自动清理和归档
 *
 * 职责分离：
 * - 日志记录：记录操作的详细信息
 * - 日志查询：提供灵活的日志查询接口
 * - 日志统计：生成操作统计报告
 * - 日志管理：自动清理和归档功能
 *
 * 最近修改：
 * - 2026-01-09: 代码质量优化 - 使用常量替代硬编码字符串，提高代码一致性 (修改者: moyin)
 * - 2026-01-09: 代码质量优化 - 拆分getStatistics长方法为多个私有方法，提高可读性 (修改者: moyin)
 * - 2026-01-08: 注释规范优化 - 修正@author字段，更新版本号和修改记录 (修改者: moyin)
 * - 2026-01-08: 注释规范优化 - 为接口添加注释，完善文档说明 (修改者: moyin)
 * - 2026-01-08: 注释规范优化 - 添加类注释，完善服务文档说明 (修改者: moyin)
 * - 2026-01-08: 代码质量优化 - 提取魔法数字为常量，重构长方法，补充导入 (修改者: moyin)
 * - 2026-01-08: 功能新增 - 创建管理员操作日志服务 (修改者: assistant)
 *
 * @author moyin
 * @version 1.4.0
 * @since 2026-01-08
 * @lastModified 2026-01-09
 */

import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { AdminOperationLog } from './admin_operation_log.entity';
import { LOG_QUERY_LIMITS, USER_QUERY_LIMITS, LOG_RETENTION, OPERATION_TYPES, OPERATION_RESULTS } from './admin_constants';

/**
 * 创建日志参数接口
 *
 * 功能描述：
 * 定义创建管理员操作日志所需的所有参数
 *
 * 使用场景：
 * - AdminOperationLogService.createLog()方法的参数类型
 * - 记录管理员操作的详细信息
 */
export interface CreateLogParams {
  adminUserId: string;
  adminUsername: string;
  operationType: keyof typeof OPERATION_TYPES;
  targetType: string;
  targetId?: string;
  operationDescription: string;
  httpMethodPath: string;
  requestParams?: Record<string, any>;
  beforeData?: Record<string, any>;
  afterData?: Record<string, any>;
  operationResult: keyof typeof OPERATION_RESULTS;
  errorMessage?: string;
  errorCode?: string;
  durationMs: number;
  clientIp?: string;
  userAgent?: string;
  requestId: string;
  context?: Record<string, any>;
  isSensitive?: boolean;
  affectedRecords?: number;
  batchId?: string;
}

/**
 * 日志查询参数接口
 *
 * 功能描述：
 * 定义查询管理员操作日志的过滤条件
 *
 * 使用场景：
 * - AdminOperationLogService.queryLogs()方法的参数类型
 * - 支持多维度的日志查询和过滤
 */
export interface LogQueryParams {
  adminUserId?: string;
  operationType?: string;
  targetType?: string;
  operationResult?: string;
  startDate?: Date;
  endDate?: Date;
  isSensitive?: boolean;
  limit?: number;
  offset?: number;
}

/**
 * 日志统计信息接口
 *
 * 功能描述：
 * 定义管理员操作日志的统计数据结构
 *
 * 使用场景：
 * - AdminOperationLogService.getStatistics()方法的返回类型
 * - 提供操作统计和分析数据
 */
export interface LogStatistics {
  totalOperations: number;
  successfulOperations: number;
  failedOperations: number;
  operationsByType: Record<string, number>;
  operationsByTarget: Record<string, number>;
  operationsByAdmin: Record<string, number>;
  averageDuration: number;
  sensitiveOperations: number;
  uniqueAdmins: number;
}

/**
 * 管理员操作日志服务
 *
 * 功能描述：
 * - 记录管理员的所有数据库操作
 * - 提供操作日志的查询和统计功能
 * - 支持敏感操作的特殊标记
 * - 实现日志的自动清理和归档
 *
 * 职责分离：
 * - 日志记录：记录操作的详细信息
 * - 日志查询：提供灵活的日志查询接口
 * - 日志统计：生成操作统计报告
 * - 日志管理：自动清理和归档功能
 *
 * 主要方法：
 * - createLog() - 创建操作日志记录
 * - queryLogs() - 查询操作日志
 * - getLogById() - 获取单个日志详情
 * - getStatistics() - 获取操作统计
 * - getSensitiveOperations() - 获取敏感操作日志
 * - getAdminOperationHistory() - 获取管理员操作历史
 * - cleanupExpiredLogs() - 清理过期日志
 *
 * 使用场景：
 * - 管理员操作审计
 * - 安全监控和异常检测
 * - 系统操作统计分析
 */
@Injectable()
export class AdminOperationLogService {
  private readonly logger = new Logger(AdminOperationLogService.name);

  constructor(
    @InjectRepository(AdminOperationLog)
    private readonly logRepository: Repository<AdminOperationLog>,
  ) {
    this.logger.log('AdminOperationLogService初始化完成');
  }

  /**
   * 创建操作日志
   *
   * @param params 日志参数
   * @returns 创建的日志记录
   */
  async createLog(params: CreateLogParams): Promise<AdminOperationLog> {
    try {
      const log = this.logRepository.create({
        admin_user_id: params.adminUserId,
        admin_username: params.adminUsername,
        operation_type: params.operationType,
        target_type: params.targetType,
        target_id: params.targetId,
        operation_description: params.operationDescription,
        http_method_path: params.httpMethodPath,
        request_params: params.requestParams,
        before_data: params.beforeData,
        after_data: params.afterData,
        operation_result: params.operationResult,
        error_message: params.errorMessage,
        error_code: params.errorCode,
        duration_ms: params.durationMs,
        client_ip: params.clientIp,
        user_agent: params.userAgent,
        request_id: params.requestId,
        context: params.context,
        is_sensitive: params.isSensitive || false,
        affected_records: params.affectedRecords || 0,
        batch_id: params.batchId,
      });

      const savedLog = await this.logRepository.save(log);

      this.logger.log('操作日志记录成功', {
        logId: savedLog.id,
        adminUserId: params.adminUserId,
        operationType: params.operationType,
        targetType: params.targetType,
        operationResult: params.operationResult
      });

      return savedLog;
    } catch (error) {
      this.logger.error('操作日志记录失败', {
        error: error instanceof Error ? error.message : String(error),
        params
      });
      throw error;
    }
  }

  /**
   * 构建查询条件
   *
   * @param queryBuilder 查询构建器
   * @param params 查询参数
   */
  private buildQueryConditions(queryBuilder: any, params: LogQueryParams): void {
    if (params.adminUserId) {
      queryBuilder.andWhere('log.admin_user_id = :adminUserId', { adminUserId: params.adminUserId });
    }

    if (params.operationType) {
      queryBuilder.andWhere('log.operation_type = :operationType', { operationType: params.operationType });
    }

    if (params.targetType) {
      queryBuilder.andWhere('log.target_type = :targetType', { targetType: params.targetType });
    }

    if (params.operationResult) {
      queryBuilder.andWhere('log.operation_result = :operationResult', { operationResult: params.operationResult });
    }

    if (params.startDate && params.endDate) {
      queryBuilder.andWhere('log.created_at BETWEEN :startDate AND :endDate', {
        startDate: params.startDate,
        endDate: params.endDate
      });
    }

    if (params.isSensitive !== undefined) {
      queryBuilder.andWhere('log.is_sensitive = :isSensitive', { isSensitive: params.isSensitive });
    }
  }

  /**
   * 查询操作日志
   *
   * @param params 查询参数
   * @returns 日志列表和总数
   */
  async queryLogs(params: LogQueryParams): Promise<{ logs: AdminOperationLog[]; total: number }> {
    try {
      const queryBuilder = this.logRepository.createQueryBuilder('log');

      // 构建查询条件
      this.buildQueryConditions(queryBuilder, params);

      // 排序
      queryBuilder.orderBy('log.created_at', 'DESC');

      // 分页
      const limit = params.limit || LOG_QUERY_LIMITS.DEFAULT_LOG_QUERY_LIMIT;
      const offset = params.offset || 0;
      queryBuilder.limit(limit).offset(offset);

      const [logs, total] = await queryBuilder.getManyAndCount();

      this.logger.log('操作日志查询成功', {
        total,
        returned: logs.length,
        params
      });

      return { logs, total };
    } catch (error) {
      this.logger.error('操作日志查询失败', {
        error: error instanceof Error ? error.message : String(error),
        params
      });
      throw error;
    }
  }

  /**
   * 根据ID获取操作日志详情
   *
   * @param id 日志ID
   * @returns 日志详情
   */
  async getLogById(id: string): Promise<AdminOperationLog | null> {
    try {
      const log = await this.logRepository.findOne({ where: { id } });

      if (log) {
        this.logger.log('操作日志详情获取成功', { logId: id });
      } else {
        this.logger.warn('操作日志不存在', { logId: id });
      }

      return log;
    } catch (error) {
      this.logger.error('操作日志详情获取失败', {
        error: error instanceof Error ? error.message : String(error),
        logId: id
      });
      throw error;
    }
  }

  /**
   * 获取基础统计数据
   *
   * @param queryBuilder 查询构建器
   * @returns 基础统计数据
   */
  private async getBasicStatistics(queryBuilder: any): Promise<{
    totalOperations: number;
    successfulOperations: number;
    failedOperations: number;
    sensitiveOperations: number;
  }> {
    const totalOperations = await queryBuilder.getCount();

    const successfulOperations = await queryBuilder
      .clone()
      .andWhere('log.operation_result = :result', { result: OPERATION_RESULTS.SUCCESS })
      .getCount();

    const failedOperations = totalOperations - successfulOperations;

    const sensitiveOperations = await queryBuilder
      .clone()
      .andWhere('log.is_sensitive = :sensitive', { sensitive: true })
      .getCount();

    return {
      totalOperations,
      successfulOperations,
      failedOperations,
      sensitiveOperations
    };
  }

  /**
   * 获取操作类型统计
   *
   * @param queryBuilder 查询构建器
   * @returns 操作类型统计
   */
  private async getOperationTypeStatistics(queryBuilder: any): Promise<Record<string, number>> {
    const operationTypeStats = await queryBuilder
      .clone()
      .select('log.operation_type', 'type')
      .addSelect('COUNT(*)', 'count')
      .groupBy('log.operation_type')
      .getRawMany();

    return operationTypeStats.reduce((acc, stat) => {
      acc[stat.type] = parseInt(stat.count);
      return acc;
    }, {} as Record<string, number>);
  }

  /**
   * 获取目标类型统计
   *
   * @param queryBuilder 查询构建器
   * @returns 目标类型统计
   */
  private async getTargetTypeStatistics(queryBuilder: any): Promise<Record<string, number>> {
    const targetTypeStats = await queryBuilder
      .clone()
      .select('log.target_type', 'type')
      .addSelect('COUNT(*)', 'count')
      .groupBy('log.target_type')
      .getRawMany();

    return targetTypeStats.reduce((acc, stat) => {
      acc[stat.type] = parseInt(stat.count);
      return acc;
    }, {} as Record<string, number>);
  }

  /**
   * 获取管理员统计
   *
   * @param queryBuilder 查询构建器
   * @returns 管理员统计
   */
  private async getAdminStatistics(queryBuilder: any): Promise<Record<string, number>> {
    const adminStats = await queryBuilder
      .clone()
      .select('log.admin_user_id', 'admin')
      .addSelect('COUNT(*)', 'count')
      .groupBy('log.admin_user_id')
      .getRawMany();

    if (!adminStats || !Array.isArray(adminStats)) {
      return {};
    }

    return adminStats.reduce((acc, stat) => {
      acc[stat.admin] = parseInt(stat.count);
      return acc;
    }, {} as Record<string, number>);
  }

  /**
   * 获取性能统计
   *
   * @param queryBuilder 查询构建器
   * @returns 性能统计
   */
  private async getPerformanceStatistics(queryBuilder: any): Promise<{
    averageDuration: number;
    uniqueAdmins: number;
  }> {
    // 平均耗时
    const avgDurationResult = await queryBuilder
      .clone()
      .select('AVG(log.duration_ms)', 'avgDuration')
      .getRawOne();

    const averageDuration = parseFloat(avgDurationResult?.avgDuration || '0');

    // 唯一管理员数量
    const uniqueAdminsResult = await queryBuilder
      .clone()
      .select('COUNT(DISTINCT log.admin_user_id)', 'uniqueAdmins')
      .getRawOne();

    const uniqueAdmins = parseInt(uniqueAdminsResult?.uniqueAdmins || '0');

    return { averageDuration, uniqueAdmins };
  }

  /**
   * 获取操作统计信息
   *
   * @param startDate 开始日期
   * @param endDate 结束日期
   * @returns 统计信息
   */
  async getStatistics(startDate?: Date, endDate?: Date): Promise<LogStatistics> {
    try {
      const queryBuilder = this.logRepository.createQueryBuilder('log');

      if (startDate && endDate) {
        queryBuilder.where('log.created_at BETWEEN :startDate AND :endDate', {
          startDate,
          endDate
        });
      }

      // 获取各类统计数据
      const basicStats = await this.getBasicStatistics(queryBuilder);
      const operationsByType = await this.getOperationTypeStatistics(queryBuilder);
      const operationsByTarget = await this.getTargetTypeStatistics(queryBuilder);
      const operationsByAdmin = await this.getAdminStatistics(queryBuilder);
      const performanceStats = await this.getPerformanceStatistics(queryBuilder);

      const statistics: LogStatistics = {
        ...basicStats,
        operationsByType,
        operationsByTarget,
        operationsByAdmin,
        ...performanceStats
      };

      this.logger.log('操作统计获取成功', statistics);

      return statistics;
    } catch (error) {
      this.logger.error('操作统计获取失败', {
        error: error instanceof Error ? error.message : String(error),
        startDate,
        endDate
      });
      throw error;
    }
  }

  /**
   * 清理过期日志
   *
   * @param daysToKeep 保留天数
   * @returns 清理的记录数
   */
  async cleanupExpiredLogs(daysToKeep: number = LOG_RETENTION.DEFAULT_DAYS): Promise<number> {
    try {
      const cutoffDate = new Date();
      cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);

      const result = await this.logRepository
        .createQueryBuilder()
        .delete()
        .where('created_at < :cutoffDate', { cutoffDate })
        .andWhere('is_sensitive = :sensitive', { sensitive: false }) // 保留敏感操作日志
        .execute();

      const deletedCount = result.affected || 0;

      this.logger.log('过期日志清理完成', {
        deletedCount,
        cutoffDate,
        daysToKeep
      });

      return deletedCount;
    } catch (error) {
      this.logger.error('过期日志清理失败', {
        error: error instanceof Error ? error.message : String(error),
        daysToKeep
      });
      throw error;
    }
  }

  /**
   * 获取管理员操作历史
   *
   * @param adminUserId 管理员用户ID
   * @param limit 限制数量
   * @returns 操作历史
   */
  async getAdminOperationHistory(adminUserId: string, limit: number = USER_QUERY_LIMITS.ADMIN_HISTORY_DEFAULT_LIMIT): Promise<AdminOperationLog[]> {
    try {
      const logs = await this.logRepository.find({
        where: { admin_user_id: adminUserId },
        order: { created_at: 'DESC' },
        take: limit
      });

      this.logger.log('管理员操作历史获取成功', {
        adminUserId,
        count: logs.length
      });

      return logs;
    } catch (error) {
      this.logger.error('管理员操作历史获取失败', {
        error: error instanceof Error ? error.message : String(error),
        adminUserId
      });
      throw error;
    }
  }

  /**
   * 获取敏感操作日志
   *
   * @param limit 限制数量
   * @param offset 偏移量
   * @returns 敏感操作日志
   */
  async getSensitiveOperations(limit: number = LOG_QUERY_LIMITS.SENSITIVE_LOG_DEFAULT_LIMIT, offset: number = 0): Promise<{ logs: AdminOperationLog[]; total: number }> {
    try {
      const [logs, total] = await this.logRepository.findAndCount({
        where: { is_sensitive: true },
        order: { created_at: 'DESC' },
        take: limit,
        skip: offset
      });

      this.logger.log('敏感操作日志获取成功', {
        total,
        returned: logs.length
      });

      return { logs, total };
    } catch (error) {
      this.logger.error('敏感操作日志获取失败', {
        error: error instanceof Error ? error.message : String(error)
      });
      throw error;
    }
  }
}