import * as plugins from '../plugins.js';
import { logger } from '../logger.js';
import { DcRouterDb } from './classes.dcrouter-db.js';

// Import document classes for cleanup
import { CachedEmail } from './documents/classes.cached.email.js';
import { CachedIPReputation } from './documents/classes.cached.ip.reputation.js';

/**
 * Configuration for the cache cleaner
 */
export interface ICacheCleanerOptions {
  /** Cleanup interval in milliseconds (default: 1 hour) */
  intervalMs?: number;
  /** Enable verbose logging */
  verbose?: boolean;
}

/**
 * CacheCleaner - Periodically removes expired documents from the cache
 *
 * Runs on a configurable interval (default: hourly) and queries each
 * collection for documents where expiresAt < now(), then deletes them.
 */
export class CacheCleaner {
  private cleanupInterval: ReturnType<typeof setInterval> | null = null;
  private isRunning: boolean = false;
  private options: Required<ICacheCleanerOptions>;
  private dcRouterDb: DcRouterDb;

  constructor(dcRouterDb: DcRouterDb, options: ICacheCleanerOptions = {}) {
    this.dcRouterDb = dcRouterDb;
    this.options = {
      intervalMs: options.intervalMs || 60 * 60 * 1000, // 1 hour default
      verbose: options.verbose || false,
    };
  }

  /**
   * Start the periodic cleanup process
   */
  public start(): void {
    if (this.isRunning) {
      logger.log('warn', 'CacheCleaner already running');
      return;
    }

    this.isRunning = true;

    // Run cleanup immediately on start
    this.runCleanup().catch((error: unknown) => {
      logger.log('error', `Initial cache cleanup failed: ${(error as Error).message}`);
    });

    // Schedule periodic cleanup
    this.cleanupInterval = setInterval(() => {
      this.runCleanup().catch((error: unknown) => {
        logger.log('error', `Cache cleanup failed: ${(error as Error).message}`);
      });
    }, this.options.intervalMs);

    logger.log(
      'info',
      `CacheCleaner started with interval: ${this.options.intervalMs / 1000 / 60} minutes`
    );
  }

  /**
   * Stop the periodic cleanup process
   */
  public stop(): void {
    if (!this.isRunning) {
      return;
    }

    if (this.cleanupInterval) {
      clearInterval(this.cleanupInterval);
      this.cleanupInterval = null;
    }

    this.isRunning = false;
    logger.log('info', 'CacheCleaner stopped');
  }

  /**
   * Run a single cleanup cycle
   */
  public async runCleanup(): Promise<void> {
    if (!this.dcRouterDb.isReady()) {
      logger.log('warn', 'DcRouterDb not ready, skipping cleanup');
      return;
    }

    const now = new Date();
    const results: { collection: string; deleted: number }[] = [];

    try {
      const emailsDeleted = await this.cleanExpiredDocuments(CachedEmail, now);
      results.push({ collection: 'CachedEmail', deleted: emailsDeleted });

      const ipReputationDeleted = await this.cleanExpiredDocuments(CachedIPReputation, now);
      results.push({ collection: 'CachedIPReputation', deleted: ipReputationDeleted });

      // Log results
      const totalDeleted = results.reduce((sum, r) => sum + r.deleted, 0);
      if (totalDeleted > 0 || this.options.verbose) {
        const summary = results
          .filter((r) => r.deleted > 0)
          .map((r) => `${r.collection}: ${r.deleted}`)
          .join(', ');
        logger.log(
          'info',
          `Cache cleanup completed. Deleted ${totalDeleted} expired documents. ${summary || 'No deletions.'}`
        );
      }
    } catch (error: unknown) {
      logger.log('error', `Cache cleanup error: ${(error as Error).message}`);
      throw error;
    }
  }

  /**
   * Clean expired documents from a specific collection using smartdata API
   */
  private async cleanExpiredDocuments<T extends { delete: () => Promise<void> }>(
    documentClass: { getInstances: (filter: any) => Promise<T[]> },
    now: Date
  ): Promise<number> {
    try {
      // Find all expired documents
      const expiredDocs = await documentClass.getInstances({
        expiresAt: { $lt: now },
      });

      // Delete each expired document
      let deletedCount = 0;
      for (const doc of expiredDocs) {
        try {
          await doc.delete();
          deletedCount++;
        } catch (deleteError: unknown) {
          logger.log('warn', `Failed to delete expired document: ${(deleteError as Error).message}`);
        }
      }

      return deletedCount;
    } catch (error: unknown) {
      logger.log('error', `Error cleaning collection: ${(error as Error).message}`);
      return 0;
    }
  }

  /**
   * Check if the cleaner is running
   */
  public isActive(): boolean {
    return this.isRunning;
  }

  /**
   * Get the cleanup interval in milliseconds
   */
  public getIntervalMs(): number {
    return this.options.intervalMs;
  }
}
