import * as plugins from '../plugins.js';

/**
 * Base class for all cached documents with TTL support
 *
 * Extends smartdata's SmartDataDbDoc to add:
 * - Automatic timestamps (createdAt, lastAccessedAt)
 * - TTL/expiration support (expiresAt)
 * - Helper methods for TTL management
 *
 * NOTE: Subclasses MUST add @svDb() decorators to createdAt, expiresAt, and lastAccessedAt
 * since decorators on abstract classes don't propagate correctly.
 */
export abstract class CachedDocument<T extends CachedDocument<T>> extends plugins.smartdata.SmartDataDbDoc<T, T> {
  /**
   * Timestamp when the document was created
   * NOTE: Subclasses must add @svDb() decorator
   */
  public createdAt: Date = new Date();

  /**
   * Timestamp when the document expires and should be cleaned up
   * NOTE: Subclasses must add @svDb() decorator
   */
  public expiresAt!: Date;

  /**
   * Timestamp of last access (for LRU-style eviction if needed)
   * NOTE: Subclasses must add @svDb() decorator
   */
  public lastAccessedAt: Date = new Date();

  /**
   * Set the TTL (time to live) for this document
   * @param ttlMs Time to live in milliseconds
   */
  public setTTL(ttlMs: number): void {
    this.expiresAt = new Date(Date.now() + ttlMs);
  }

  /**
   * Set TTL using days
   * @param days Number of days until expiration
   */
  public setTTLDays(days: number): void {
    this.setTTL(days * 24 * 60 * 60 * 1000);
  }

  /**
   * Set TTL using hours
   * @param hours Number of hours until expiration
   */
  public setTTLHours(hours: number): void {
    this.setTTL(hours * 60 * 60 * 1000);
  }

  /**
   * Check if this document has expired
   */
  public isExpired(): boolean {
    if (!this.expiresAt) {
      return false; // No expiration set
    }
    return new Date() > this.expiresAt;
  }

  /**
   * Update the lastAccessedAt timestamp
   */
  public touch(): void {
    this.lastAccessedAt = new Date();
  }

  /**
   * Get remaining TTL in milliseconds
   * Returns 0 if expired, -1 if no expiration set
   */
  public getRemainingTTL(): number {
    if (!this.expiresAt) {
      return -1;
    }
    const remaining = this.expiresAt.getTime() - Date.now();
    return remaining > 0 ? remaining : 0;
  }

  /**
   * Extend the TTL by the specified milliseconds from now
   * @param ttlMs Additional time to live in milliseconds
   */
  public extendTTL(ttlMs: number): void {
    this.expiresAt = new Date(Date.now() + ttlMs);
  }

  /**
   * Set the document to never expire (100 years in the future)
   */
  public setNeverExpires(): void {
    this.expiresAt = new Date(Date.now() + 100 * 365 * 24 * 60 * 60 * 1000);
  }
}

/**
 * TTL constants in milliseconds
 */
export const TTL = {
  HOURS_1: 1 * 60 * 60 * 1000,
  HOURS_24: 24 * 60 * 60 * 1000,
  DAYS_7: 7 * 24 * 60 * 60 * 1000,
  DAYS_30: 30 * 24 * 60 * 60 * 1000,
  DAYS_90: 90 * 24 * 60 * 60 * 1000,
} as const;
