import { ensureUserExists } from '../db';
import { getDb } from '../db/locator';
import { normalizeWhatsAppId } from '../utils/whatsapp';
import { Metrics } from './metrics';

export class IdentityService {
  // Caché en memoria como respaldo si la tabla user_aliases no está disponible (tests o migraciones incompletas)
  private static readonly inMemoryAliases = new Map<string, string>();

  /**
   * Registra o actualiza un alias (LID u otro identificador) apuntando al user_id real (número).
   * Devuelve true si se insertó/actualizó, false si no se pudo o no era necesario.
   */
  static upsertAlias(alias: string | null | undefined, userId: string | null | undefined, source?: string | null): boolean {
    const a = normalizeWhatsAppId(alias || '');
    const u = normalizeWhatsAppId(userId || '');
    if (!a || !u || a === u) return false;
    // Asegurar que el user_id numérico exista para no violar la FK (user_aliases.user_id -> users.id)
    try { ensureUserExists(u, getDb()); } catch {}
    try {
      getDb().prepare(`
        INSERT INTO user_aliases (alias, user_id, source, created_at, updated_at)
        VALUES (?, ?, ?, strftime('%Y-%m-%d %H:%M:%f', 'now'), strftime('%Y-%m-%d %H:%M:%f', 'now'))
        ON CONFLICT(alias) DO UPDATE SET
          user_id = excluded.user_id,
          source = COALESCE(excluded.source, source),
          updated_at = excluded.updated_at
      `).run(a, u, source ?? null);
    } catch (e) {
      // Si la tabla no existe o hay error de DB, continuamos con la caché en memoria
      try { Metrics.inc('identity_alias_upsert_errors_total'); } catch {}
      try {
        if (String(process.env.NODE_ENV || '').toLowerCase() !== 'test') {
          console.warn('[IdentityService.upsertAlias] Falló persistir alias en DB (se mantiene en caché en memoria):', e);
        }
      } catch {}
    }
    // Actualizar siempre la caché en memoria para disponibilizar el alias inmediatamente
    this.inMemoryAliases.set(a, u);
    try { Metrics.inc('identity_alias_upserts_total'); } catch {}
    return true;
  }

  /**
   * Resuelve un alias a su número real. Devuelve null si no hay mapeo.
   */
  static resolveAliasOrNull(id: string | null | undefined): string | null {
    const n = normalizeWhatsAppId(id || '');
    if (!n) return null;

    // Primero, comprobar la caché en memoria
    const mem = this.inMemoryAliases.get(n);
    if (mem) {
      try { Metrics.inc('identity_alias_resolved_total'); } catch {}
      return mem;
    }

    // Después, intentar en la base de datos
    try {
      const row = getDb().prepare(`SELECT user_id FROM user_aliases WHERE alias = ?`).get(n) as { user_id?: string } | undefined;
      if (row?.user_id) {
        const v = String(row.user_id);
        // Mantener caché en memoria para futuras resoluciones rápidas
        this.inMemoryAliases.set(n, v);
        try { Metrics.inc('identity_alias_resolved_total'); } catch {}
        return v;
      }
      try { Metrics.inc('identity_alias_unresolved_total'); } catch {}
      return null;
    } catch {
      // En caso de error de DB, consideramos no resuelto
      try { Metrics.inc('identity_alias_unresolved_total'); } catch {}
      return null;
    }
  }

  /**
   * Resuelve en lote varios ids (devuelve solo los que tengan mapeo).
   */
  static resolveMany(ids: Array<string | null | undefined>): Map<string, string> {
    const map = new Map<string, string>();
    for (const id of ids) {
      const n = normalizeWhatsAppId(id || '');
      if (!n) continue;
      const r = this.resolveAliasOrNull(n);
      if (r) map.set(n, r);
    }
    return map;
  }
}
