import { logger } from '../logging.ts';
import type { CacheDb } from './classes.cachedb.ts';

// deno-lint-ignore no-explicit-any
type DocumentClass = { getInstances: (filter: any) => Promise<{ delete: () => Promise<void> }[]> };

const DEFAULT_INTERVAL_MS = 60 * 60 * 1000; // 1 hour

/**
 * Periodically cleans up expired cached documents.
 */
export class CacheCleaner {
  private intervalId: number | null = null;
  private intervalMs: number;
  private documentClasses: DocumentClass[] = [];
  private cacheDb: CacheDb;

  constructor(cacheDb: CacheDb, intervalMs = DEFAULT_INTERVAL_MS) {
    this.cacheDb = cacheDb;
    this.intervalMs = intervalMs;
  }

  /** Register a document class for cleanup */
  registerClass(cls: DocumentClass): void {
    this.documentClasses.push(cls);
  }

  start(): void {
    if (this.intervalId !== null) return;
    this.intervalId = setInterval(() => {
      this.clean().catch((err) => {
        logger.error(`CacheCleaner error: ${err}`);
      });
    }, this.intervalMs);
    // Unref so the interval doesn't prevent process exit
    Deno.unrefTimer(this.intervalId);
    logger.debug(`CacheCleaner started (interval: ${this.intervalMs}ms)`);
  }

  stop(): void {
    if (this.intervalId !== null) {
      clearInterval(this.intervalId);
      this.intervalId = null;
      logger.debug('CacheCleaner stopped');
    }
  }

  /** Run a single cleanup pass */
  async clean(): Promise<number> {
    const now = Date.now();
    let totalDeleted = 0;
    for (const cls of this.documentClasses) {
      try {
        const expired = await cls.getInstances({ expiresAt: { $lt: now } });
        for (const doc of expired) {
          await doc.delete();
          totalDeleted++;
        }
      } catch (err) {
        logger.error(`CacheCleaner: failed to clean class: ${err}`);
      }
    }
    if (totalDeleted > 0) {
      logger.debug(`CacheCleaner: deleted ${totalDeleted} expired document(s)`);
    }
    return totalDeleted;
  }
}
