import IORedis, { type Redis, type RedisOptions } from 'ioredis';

import { loadConfig } from '@/app/config';
import { logger } from '@/shared/logger';

let cached: Redis | null = null;

/**
 * Lazy singleton ioredis connection shared by every BullMQ queue and worker.
 *
 * BullMQ requires `maxRetriesPerRequest: null` and `enableReadyCheck: false`
 * for worker connections; we set those here so the same connection is safe
 * to reuse for queues, workers, and the /health/deep ping.
 */
export function getRedis(): Redis {
  if (cached) return cached;

  const { REDIS_URL } = loadConfig();
  const options: RedisOptions = {
    maxRetriesPerRequest: null,
    enableReadyCheck: false,
    lazyConnect: false,
  };

  const conn = new IORedis(REDIS_URL, options);
  conn.on('error', (err) => {
    logger.error('redis: connection error', { err: err.message });
  });
  conn.on('connect', () => {
    logger.info('redis: connected', { url: redactedUrl(REDIS_URL) });
  });

  cached = conn;
  return conn;
}

export async function pingRedis(): Promise<void> {
  const reply = await getRedis().ping();
  if (reply !== 'PONG') throw new Error(`unexpected ping reply: ${reply}`);
}

export async function closeRedis(): Promise<void> {
  if (!cached) return;
  await cached.quit();
  cached = null;
}

function redactedUrl(url: string): string {
  try {
    const u = new URL(url);
    if (u.password) u.password = '***';
    return u.toString();
  } catch {
    return url;
  }
}
