import { Database } from 'bun:sqlite';
import { beforeAll, beforeEach, afterAll, describe, expect, test } from 'bun:test';
import { initializeDatabase } from '../../../src/db';
import { GroupSyncService } from '../../../src/services/group-sync';
import { setDb, resetDb } from '../../../src/db/locator';

describe('GroupSyncService - reconcileGroupMembers', () => {
  let memdb: Database;

  beforeAll(() => {
    memdb = new Database(':memory:');
    memdb.exec('PRAGMA foreign_keys = ON;');
    initializeDatabase(memdb);
    setDb(memdb);
  });

  afterAll(() => {
    resetDb();
    memdb.close();
  });

  beforeEach(() => {
    setDb(memdb);
    try { GroupSyncService.activeGroupsCache.clear(); } catch {}
    // Limpiar tablas relevantes entre tests
    memdb.exec('DELETE FROM group_members');
    memdb.exec('DELETE FROM users');
    memdb.exec('DELETE FROM groups');

    // Crear grupo base activo
    memdb.prepare(`INSERT INTO groups (id, community_id, name) VALUES (?, ?, ?)`)
      .run('123@g.us', 'community-1', 'Grupo 123');
  });

  function getMember(userId: string) {
    return memdb.prepare(`
      SELECT group_id, user_id, is_admin, is_active, first_seen_at, last_seen_at, last_role_change_at
      FROM group_members
      WHERE group_id = ? AND user_id = ?
    `).get('123@g.us', userId) as any;
  }

  test('inserta miembros y marca activos en la primera reconciliación', () => {
    const res = GroupSyncService.reconcileGroupMembers('123@g.us', [
      { userId: '111', isAdmin: true },
      { userId: '222', isAdmin: false }
    ], '2025-01-01 00:00:00.000');

    expect(res).toEqual({ added: 2, updated: 0, deactivated: 0 });

    const m1 = getMember('111');
    const m2 = getMember('222');

    expect(m1).toBeDefined();
    expect(m1.is_active).toBe(1);
    expect(m1.is_admin).toBe(1);
    expect(m1.first_seen_at).toBe('2025-01-01 00:00:00.000');
    expect(m1.last_seen_at).toBe('2025-01-01 00:00:00.000');

    expect(m2).toBeDefined();
    expect(m2.is_active).toBe(1);
    expect(m2.is_admin).toBe(0);
  });

  test('actualiza roles, desactiva ausentes y añade nuevos en reconciliaciones posteriores', () => {
    // Primera pasada
    GroupSyncService.reconcileGroupMembers('123@g.us', [
      { userId: '111', isAdmin: true },
      { userId: '222', isAdmin: false }
    ], '2025-01-01 00:00:00.000');

    // Segunda pasada con cambios: 111 pierde admin, 222 desaparece, 333 aparece
    const res2 = GroupSyncService.reconcileGroupMembers('123@g.us', [
      { userId: '111', isAdmin: false },
      { userId: '333', isAdmin: false }
    ], '2025-01-02 00:00:00.000');

    expect(res2).toEqual({ added: 1, updated: 1, deactivated: 1 });

    const m111 = getMember('111');
    const m222 = getMember('222');
    const m333 = getMember('333');

    expect(m111.is_active).toBe(1);
    expect(m111.is_admin).toBe(0);
    expect(m111.last_role_change_at).toBe('2025-01-02 00:00:00.000');
    expect(m222.is_active).toBe(0);
    expect(m333.is_active).toBe(1);
    expect(m333.is_admin).toBe(0);
  });

  test('idempotencia: aplicar mismo snapshot no altera contadores y actualiza last_seen_at', () => {
    GroupSyncService.reconcileGroupMembers('123@g.us', [
      { userId: '111', isAdmin: false },
      { userId: '333', isAdmin: false }
    ], '2025-01-02 00:00:00.000');

    const res3 = GroupSyncService.reconcileGroupMembers('123@g.us', [
      { userId: '111', isAdmin: false },
      { userId: '333', isAdmin: false }
    ], '2025-01-03 00:00:00.000');

    expect(res3).toEqual({ added: 0, updated: 0, deactivated: 0 });

    const m111 = getMember('111');
    const m333 = getMember('333');

    expect(m111.last_seen_at).toBe('2025-01-03 00:00:00.000');
    expect(m333.last_seen_at).toBe('2025-01-03 00:00:00.000');
  });
});
