import { Types } from 'mongoose';
import LoggingModel, { LogLevel } from '../../models/Logging';

export interface CreateLogData {
  module: string;
  level: LogLevel;
  action: string;
  admin_id?: string;
  user_id?: string;
  metadata?: Record<string, any>;
  ip_address?: string;
  user_agent?: string;
  error_details?: any;
}

export interface FilterLogsParams {
  module?: string;
  level?: LogLevel;
  admin_id?: string;
  user_id?: string;
  startDate?: Date;
  endDate?: Date;
  page?: number;
  limit?: number;
}

/**
 * Logging Repository
 * Handles all database operations for logging
 */
export class LoggingRepository {
  /**
   * Create a new log entry
   */
  static async createLog(logData: CreateLogData) {
    const log = new LoggingModel({
      ...logData,
      admin_id: logData.admin_id ? new Types.ObjectId(logData.admin_id) : undefined,
      user_id: logData.user_id ? new Types.ObjectId(logData.user_id) : undefined,
    });
    return await log.save();
  }

  /**
   * Find logs with filtering options
   */
  static async findLogs(params: FilterLogsParams) {
    const {
      module,
      level,
      admin_id,
      user_id,
      startDate,
      endDate,
      page = 1,
      limit = 50,
    } = params;

    const query: any = {};

    // Build query filters
    if (module) {
      query.module = module;
    }

    if (level) {
      query.level = level;
    }

    if (admin_id) {
      query.admin_id = new Types.ObjectId(admin_id);
    }

    if (user_id) {
      query.user_id = new Types.ObjectId(user_id);
    }

    // Date range filter
    if (startDate || endDate) {
      query.timestamp = {};
      if (startDate) {
        query.timestamp.$gte = startDate;
      }
      if (endDate) {
        query.timestamp.$lte = endDate;
      }
    }

    // Calculate pagination
    const skip = (page - 1) * limit;

    // Execute query with pagination
    const logs = await LoggingModel.find(query)
      .sort({ timestamp: -1 })
      .skip(skip)
      .limit(limit)
      .populate('admin_id', 'email first_name last_name')
      .populate('user_id', 'email first_name last_name')
      .lean();

    // Get total count for pagination
    const total = await LoggingModel.countDocuments(query);

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

  /**
   * Find logs by admin ID
   */
  static async findLogsByAdminId(adminId: string, params?: Omit<FilterLogsParams, 'admin_id'>) {
    return this.findLogs({
      ...params,
      admin_id: adminId,
    });
  }

  /**
   * Find logs by module
   */
  static async findLogsByModule(module: string, params?: Omit<FilterLogsParams, 'module'>) {
    return this.findLogs({
      ...params,
      module,
    });
  }

  /**
   * Find logs by level
   */
  static async findLogsByLevel(level: LogLevel, params?: Omit<FilterLogsParams, 'level'>) {
    return this.findLogs({
      ...params,
      level,
    });
  }

  /**
   * Get log statistics
   */
  static async getLogStatistics(params?: {
    startDate?: Date;
    endDate?: Date;
    module?: string;
  }) {
    const query: any = {};

    if (params?.startDate || params?.endDate) {
      query.timestamp = {};
      if (params.startDate) {
        query.timestamp.$gte = params.startDate;
      }
      if (params.endDate) {
        query.timestamp.$lte = params.endDate;
      }
    }

    if (params?.module) {
      query.module = params.module;
    }

    const stats = await LoggingModel.aggregate([
      { $match: query },
      {
        $group: {
          _id: '$level',
          count: { $sum: 1 },
        },
      },
      {
        $group: {
          _id: null,
          total: { $sum: '$count' },
          levels: {
            $push: {
              level: '$_id',
              count: '$count',
            },
          },
        },
      },
      {
        $project: {
          _id: 0,
          total: 1,
          levels: 1,
        },
      },
    ]);

    const moduleStats = await LoggingModel.aggregate([
      { $match: query },
      {
        $group: {
          _id: '$module',
          count: { $sum: 1 },
        },
      },
      {
        $sort: { count: -1 },
      },
      {
        $limit: 10,
      },
    ]);

    return {
      total: stats[0]?.total || 0,
      byLevel: stats[0]?.levels || [],
      byModule: moduleStats,
    };
  }

  /**
   * Delete old logs (for cleanup operations)
   */
  static async deleteOldLogs(olderThanDays: number) {
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - olderThanDays);

    const result = await LoggingModel.deleteMany({
      timestamp: { $lt: cutoffDate },
      level: { $in: ['INFO', 'DEBUG'] }, // Only delete non-critical logs
    });

    return result.deletedCount;
  }
}
