import { Injectable, OnModuleDestroy } from '@nestjs/common';
import Redis from 'ioredis';
import { IPresenceService } from '../../domain/ports/presence.service.interface';

const ONLINE_KEY = 'genex:presence:online';
const DAU_KEY_PREFIX = 'genex:dau:';
const ONLINE_WINDOW = 180; // 3 minutes

@Injectable()
export class PresenceRedisService implements IPresenceService, OnModuleDestroy {
  private readonly redis: Redis;

  constructor() {
    this.redis = new Redis({
      host: process.env.REDIS_HOST || 'localhost',
      port: parseInt(process.env.REDIS_PORT || '6379', 10),
      password: process.env.REDIS_PASSWORD || undefined,
      db: parseInt(process.env.REDIS_DB || '0', 10),
    });
  }

  async onModuleDestroy() {
    await this.redis.quit();
  }

  /** Update user heartbeat timestamp */
  async updatePresence(userId: string): Promise<void> {
    const now = Math.floor(Date.now() / 1000);
    await this.redis.zadd(ONLINE_KEY, now, userId);
  }

  /** Count users online within window */
  async countOnline(): Promise<number> {
    const threshold = Math.floor(Date.now() / 1000) - ONLINE_WINDOW;
    return this.redis.zcount(ONLINE_KEY, threshold, '+inf');
  }

  /** Add user/installId to HyperLogLog DAU */
  async addDauIdentifier(date: string, identifier: string): Promise<void> {
    const key = `${DAU_KEY_PREFIX}${date}`;
    await this.redis.pfadd(key, identifier);
    // Auto-expire after 48 hours
    await this.redis.expire(key, 48 * 3600);
  }

  /** Get approximate DAU from HyperLogLog */
  async getApproxDau(date: string): Promise<number> {
    return this.redis.pfcount(`${DAU_KEY_PREFIX}${date}`);
  }

  /** Clean up expired presence data (>24h old) */
  async cleanupExpired(): Promise<number> {
    const cutoff = Math.floor(Date.now() / 1000) - 24 * 3600;
    return this.redis.zremrangebyscore(ONLINE_KEY, '-inf', cutoff);
  }

  getWindowSeconds(): number {
    return ONLINE_WINDOW;
  }
}
