import { describe, it, expect, beforeAll, beforeEach } from 'bun:test';
import { Database } from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { Metrics } from '../../../src/services/metrics';
import { setDb } from '../../../src/db/locator';

describe('CommandService - t nueva (A2: fallback menciones)', () => {
  let memdb: Database;

  beforeAll(() => {
    memdb = new Database(':memory:');
    initializeDatabase(memdb);
    setDb(memdb);
  });

  beforeEach(() => {
    process.env.NODE_ENV = 'test';
    process.env.METRICS_ENABLED = 'true';
    process.env.CHATBOT_PHONE_NUMBER = '1234567890';
    process.env.ONBOARDING_FALLBACK_MIN_DIGITS = '8';
    Metrics.reset();

    memdb.exec(`
      DELETE FROM task_assignments;
      DELETE FROM tasks;
      DELETE FROM users;
      DELETE FROM user_preferences;
    `);
  });

  function getLastTaskId(): number {
    const row = memdb.prepare(`SELECT id FROM tasks ORDER BY id DESC LIMIT 1`).get() as any;
    return row ? Number(row.id) : 0;
  }

  function getAssignees(taskId: number): string[] {
    const rows = memdb.prepare(`SELECT user_id FROM task_assignments WHERE task_id = ? ORDER BY assigned_at ASC`).all(taskId) as any[];
    return rows.map(r => String(r.user_id));
  }

  it('asigna por mención de JID real sin alias (fallback a dígitos)', async () => {
    const res = await CommandService.handle({
      sender: '111',
      groupId: '', // DM
      message: 't n Tarea por mención',
      mentions: ['34600123456@s.whatsapp.net'],
    });
    expect(res.length).toBeGreaterThan(0);

    const taskId = getLastTaskId();
    expect(taskId).toBeGreaterThan(0);
    const assignees = getAssignees(taskId);
    expect(assignees).toContain('34600123456');
  });

  it('asigna por token @ con + (fallback y normalización de +)', async () => {
    const res = await CommandService.handle({
      sender: '222',
      groupId: '',
      message: 't nueva Tarea token @+34600123456',
      mentions: [],
    });
    expect(res.length).toBeGreaterThan(0);

    const taskId = getLastTaskId();
    const assignees = getAssignees(taskId);
    expect(assignees).toContain('34600123456');
  });

  it('mención/tokens irrecuperables: no bloquea, incrementa métrica', async () => {
    const res = await CommandService.handle({
      sender: '333',
      groupId: '',
      message: 't n Mixta @34600123456 @lid-opaque',
      mentions: [],
    });
    expect(res.length).toBeGreaterThan(0);

    const taskId = getLastTaskId();
    const assignees = getAssignees(taskId);
    expect(assignees).toContain('34600123456');

    const prom = Metrics.render('prom');
    expect(prom).toContain('onboarding_assign_failures_total');
    expect(prom).toContain('source="tokens"');
  });

  it('filtra el número del bot entre candidatos', async () => {
    // CHATBOT_PHONE_NUMBER = '1234567890' (ver beforeEach)
    const res = await CommandService.handle({
      sender: '444',
      groupId: '',
      message: 't n Asignar @1234567890 @34600123456',
      mentions: [],
    });
    expect(res.length).toBeGreaterThan(0);

    const taskId = getLastTaskId();
    const assignees = getAssignees(taskId);
    expect(assignees).toContain('34600123456');
    expect(assignees).not.toContain('1234567890');
  });

  it('deduplica cuando el mismo usuario aparece por mención y token', async () => {
    const res = await CommandService.handle({
      sender: '555',
      groupId: '',
      message: 't n Dedupe @34600123456',
      mentions: ['34600123456@s.whatsapp.net'],
    });
    expect(res.length).toBeGreaterThan(0);

    const taskId = getLastTaskId();
    const assignees = getAssignees(taskId);
    // Solo un registro para el mismo usuario
    const count = assignees.filter(v => v === '34600123456').length;
    expect(count).toBe(1);
  });
});
