/**
 * Homepage Stats EventBus Listener
 *
 * Maintains real-time counters in Redis for the homepage dashboard and
 * invalidates the homepage cache when underlying data changes.
 *
 * Redis keys:
 *   homepage:counter:emails        — total campaign emails sent
 *   homepage:counter:signups       — total shift signups
 *   homepage:counter:donations     — total donation count
 *   homepage:counter:donations:amt — total donation amount (cents)
 *   homepage:counter:responses     — total campaign responses
 *   homepage:counter:canvass       — total canvass visits
 *   homepage:counter:videos        — total video views
 *   homepage:recent:{type}         — recent activity list (capped at 20)
 *
 * Cache invalidation:
 *   Deletes `homepage:public` when shifts, campaigns, or media change
 *   so the next request rebuilds with fresh data.
 *
 * No feature guard — always active (counters are ephemeral in Redis).
 */

import { eventBus } from '../event-bus.service';
import { logger } from '../../utils/logger';

let redisPromise: ReturnType<typeof getRedis> | null = null;
async function getRedis() {
  const { redis } = await import('../../config/redis');
  return redis;
}
function lazyRedis() {
  if (!redisPromise) redisPromise = getRedis();
  return redisPromise;
}

const HOMEPAGE_CACHE_KEY = 'homepage:public';

/** Increment a counter and optionally invalidate the homepage cache. */
async function incrCounter(key: string, invalidateCache = false): Promise<void> {
  try {
    const redis = await lazyRedis();
    await redis.incr(`homepage:counter:${key}`);
    if (invalidateCache) await redis.del(HOMEPAGE_CACHE_KEY);
  } catch (err) {
    logger.debug(`Homepage counter increment failed (${key}):`, err);
  }
}

/** Push a recent activity entry to a capped list. */
async function pushRecent(type: string, entry: Record<string, unknown>): Promise<void> {
  try {
    const redis = await lazyRedis();
    const key = `homepage:recent:${type}`;
    await redis.lpush(key, JSON.stringify({ ...entry, at: new Date().toISOString() }));
    await redis.ltrim(key, 0, 19); // keep last 20
    await redis.expire(key, 86400); // expire after 24h
  } catch {
    // silent
  }
}

/** Invalidate homepage cache without incrementing anything. */
async function invalidateCache(): Promise<void> {
  try {
    const redis = await lazyRedis();
    await redis.del(HOMEPAGE_CACHE_KEY);
  } catch {
    // silent
  }
}

export function registerHomepageStatsListener(): void {
  // --- Counter increments ---

  eventBus.subscribe('campaign.email.sent', 'homepage:email-sent', async () => {
    await incrCounter('emails');
  });

  eventBus.subscribe('shift.signup.created', 'homepage:shift-signup', async (payload) => {
    await incrCounter('signups', true); // invalidate — signup count visible on homepage
    await pushRecent('signups', { name: payload.userName, shift: payload.shiftTitle });
  });

  eventBus.subscribe('payment.donation.completed', 'homepage:donation', async (payload) => {
    await incrCounter('donations');
    try {
      const redis = await lazyRedis();
      await redis.incrby('homepage:counter:donations:amt', payload.amountCents);
    } catch { /* silent */ }
    await pushRecent('donations', { name: payload.name, amount: payload.amountCents });
  });

  eventBus.subscribe('response.submitted', 'homepage:response', async (payload) => {
    await incrCounter('responses');
    await pushRecent('responses', { campaign: payload.campaignTitle, rep: payload.representativeName });
  });

  eventBus.subscribe('canvass.visit.recorded', 'homepage:canvass', async () => {
    await incrCounter('canvass');
  });

  eventBus.subscribe('media.video.viewed', 'homepage:video-view', async () => {
    await incrCounter('videos');
  });

  // --- Cache invalidation (data visible on homepage changed) ---

  eventBus.subscribe('shift.created', 'homepage:shift-changed', async () => {
    await invalidateCache();
  });

  eventBus.subscribe('shift.deleted', 'homepage:shift-deleted', async () => {
    await invalidateCache();
  });

  eventBus.subscribe('campaign.published', 'homepage:campaign-published', async () => {
    await invalidateCache();
  });

  eventBus.subscribe('campaign.status.changed', 'homepage:campaign-status', async () => {
    await invalidateCache();
  });

  eventBus.subscribe('media.video.published', 'homepage:video-published', async () => {
    await invalidateCache();
  });

  eventBus.subscribe('ticketed-event.published', 'homepage:event-published', async () => {
    await invalidateCache();
  });
}

/**
 * Utility functions for reading homepage stats from Redis.
 * Can be imported by the homepage service for real-time counters.
 */
export const homepageStats = {
  /** Get all counter values */
  async getCounters(): Promise<Record<string, number>> {
    try {
      const redis = await lazyRedis();
      const keys = [
        'homepage:counter:emails',
        'homepage:counter:signups',
        'homepage:counter:donations',
        'homepage:counter:donations:amt',
        'homepage:counter:responses',
        'homepage:counter:canvass',
        'homepage:counter:videos',
      ];
      const values = await redis.mget(...keys);
      return {
        totalEmailsSent: parseInt(values[0] ?? '0', 10),
        totalShiftSignups: parseInt(values[1] ?? '0', 10),
        totalDonations: parseInt(values[2] ?? '0', 10),
        totalDonationAmountCents: parseInt(values[3] ?? '0', 10),
        totalResponses: parseInt(values[4] ?? '0', 10),
        totalCanvassVisits: parseInt(values[5] ?? '0', 10),
        totalVideoViews: parseInt(values[6] ?? '0', 10),
      };
    } catch {
      return {};
    }
  },

  /** Get recent activity of a given type */
  async getRecent(type: string, limit = 10): Promise<Array<Record<string, unknown>>> {
    try {
      const redis = await lazyRedis();
      const items = await redis.lrange(`homepage:recent:${type}`, 0, limit - 1);
      return items.map(item => JSON.parse(item));
    } catch {
      return [];
    }
  },
};
