import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import { Database } from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { ResponseQueue } from '../../../src/services/response-queue';
import { setDb, resetDb } from '../../../src/db/locator';

const ORIGINAL_FETCH = globalThis.fetch;
const envBackup = { ...process.env };

describe('ResponseQueue - jobs de reacción (enqueue + sendOne)', () => {
  let memdb: Database;
  let captured: { url?: string; payload?: any } = {};

  beforeEach(() => {
    process.env = {
      ...envBackup,
      NODE_ENV: 'test',
      EVOLUTION_API_URL: 'http://evolution.test',
      EVOLUTION_API_INSTANCE: 'instance-1',
      EVOLUTION_API_KEY: 'apikey',
      RQ_REACTIONS_MAX_ATTEMPTS: '3',
    };

    memdb = new Database(':memory:');
    memdb.exec('PRAGMA foreign_keys = ON;');
    initializeDatabase(memdb);

    setDb(memdb);

    globalThis.fetch = async (url: RequestInfo | URL, init?: RequestInit) => {
      captured.url = String(url);
      try {
        captured.payload = init?.body ? JSON.parse(String(init.body)) : null;
      } catch {
        captured.payload = null;
      }
      return new Response(JSON.stringify({ ok: true }), {
        status: 200,
        headers: { 'Content-Type': 'application/json' }
      });
    };

    memdb.exec('DELETE FROM response_queue');
    captured = {};
  });

  afterEach(() => {
    globalThis.fetch = ORIGINAL_FETCH;
    process.env = envBackup;
    try { resetDb(); memdb.close(); } catch {}
  });

  it('enqueueReaction aplica idempotencia por (chatId, messageId, emoji) en ventana 24h', async () => {
    await ResponseQueue.enqueueReaction('123@g.us', 'MSG-1', '🤖');
    await ResponseQueue.enqueueReaction('123@g.us', 'MSG-1', '🤖'); // duplicado → ignorar

    const cnt = memdb.prepare(`SELECT COUNT(*) AS c FROM response_queue`).get() as any;
    expect(Number(cnt.c)).toBe(1);

    // Mismo chat y mensaje, emoji distinto → debe insertar
    await ResponseQueue.enqueueReaction('123@g.us', 'MSG-1', '⚠️');
    const cnt2 = memdb.prepare(`SELECT COUNT(*) AS c FROM response_queue`).get() as any;
    expect(Number(cnt2.c)).toBe(2);
  });

  it('sendOne con metadata.kind === "reaction" usa /message/sendReaction y payload esperado', async () => {
    const item = {
      id: 42,
      recipient: '123@g.us',
      message: '', // no se usa para reaction
      attempts: 0,
      metadata: JSON.stringify({ kind: 'reaction', emoji: '🤖', chatId: '123@g.us', messageId: 'MSG-99' }),
    };

    const res = await ResponseQueue.sendOne(item as any);
    expect(res.ok).toBe(true);

    expect(captured.url?.includes('/message/sendReaction/instance-1')).toBe(true);
    expect(captured.payload).toBeDefined();
    expect(captured.payload.reaction).toBe('🤖');
    expect(captured.payload.key).toEqual({ remoteJid: '123@g.us', fromMe: false, id: 'MSG-99' });
  });

  it('sendOne incluye key.participant cuando viene en metadata (grupo, fromMe:false)', async () => {
    const item = {
      id: 43,
      recipient: '120363401791776728@g.us',
      message: '',
      attempts: 0,
      metadata: JSON.stringify({
        kind: 'reaction',
        emoji: '✅',
        chatId: '120363401791776728@g.us',
        messageId: 'MSG-100',
        participant: '34650861805:32@s.whatsapp.net',
        fromMe: false
      }),
    };

    const res = await ResponseQueue.sendOne(item as any);
    expect(res.ok).toBe(true);

    expect(captured.url?.includes('/message/sendReaction/instance-1')).toBe(true);
    expect(captured.payload).toBeDefined();
    expect(captured.payload.reaction).toBe('✅');
    expect(captured.payload.key).toEqual({
      remoteJid: '120363401791776728@g.us',
      fromMe: false,
      id: 'MSG-100',
      participant: '34650861805:32@s.whatsapp.net'
    });
  });
});
