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

let testDb: Database;
let originalAdd: any;

import { SimulatedResponseQueue } from '../../helpers/queue';

const createTestRequest = (payload: any) =>
  new Request('http://localhost:3007', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });

describe('WebhookServer - /admin aprobación en modo enforce', () => {
  const envBackup = process.env;

  beforeAll(() => {
    testDb = new Database(':memory:');
    initializeDatabase(testDb);
    originalAdd = (ResponseQueue as any).add;
  });

  afterAll(() => {
    (ResponseQueue as any).add = originalAdd;
    resetDb();
    testDb.close();
  });

  beforeEach(() => {
    process.env = {
      ...envBackup,
      NODE_ENV: 'test',
      GROUP_GATING_MODE: 'enforce',
      ADMIN_USERS: '1234567890'
    };
    SimulatedResponseQueue.clear();
    (ResponseQueue as any).add = SimulatedResponseQueue.add;
    WebhookServer.dbInstance = testDb;
    setDb(testDb);

    testDb.exec('DELETE FROM response_queue');
    testDb.exec('DELETE FROM allowed_groups');
    testDb.exec('DELETE FROM users');
  });

  afterEach(() => {
    process.env = envBackup;
  });

  test('admin puede habilitar el grupo actual incluso si no está allowed', async () => {
    const payload = {
      event: 'messages.upsert',
      instance: 'test-instance',
      data: {
        key: {
          remoteJid: 'new-group@g.us',
          participant: '1234567890@s.whatsapp.net'
        },
        message: { conversation: '/admin habilitar-aquí' }
      }
    };

    const res = await WebhookServer.handleRequest(createTestRequest(payload));
    expect(res.status).toBe(200);

    // Debe haber respuesta de confirmación encolada
    expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);

    // El grupo debe figurar como allowed
    const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'new-group@g.us'`).get() as any;
    expect(row && String(row.status)).toBe('allowed');
  });

  test('no admin no puede usar /admin', async () => {
    process.env.ADMIN_USERS = '5555555555';

    const payload = {
      event: 'messages.upsert',
      instance: 'test-instance',
      data: {
        key: {
          remoteJid: 'another-group@g.us',
          participant: '1234567890@s.whatsapp.net'
        },
        message: { conversation: '/admin habilitar-aquí' }
      }
    };

    const res = await WebhookServer.handleRequest(createTestRequest(payload));
    expect(res.status).toBe(200);

    // Debe haber una respuesta indicando no autorizado
    const out = SimulatedResponseQueue.get();
    expect(out.length).toBe(1);
    expect(String(out[0].message).toLowerCase()).toContain('no estás autorizado');

    // Y el grupo no debe estar allowed
    const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'another-group@g.us'`).get() as any;
    expect(row == null).toBe(true);
  });

  test('admin puede habilitar el grupo actual con alias /admin enable', async () => {
    const payload = {
      event: 'messages.upsert',
      instance: 'test-instance',
      data: {
        key: {
          remoteJid: 'new-group-alias@g.us',
          participant: '1234567890@s.whatsapp.net'
        },
        message: { conversation: '/admin enable' }
      }
    };

    const res = await WebhookServer.handleRequest(createTestRequest(payload));
    expect(res.status).toBe(200);

    // Debe haber respuesta de confirmación encolada
    expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);

    // El grupo debe figurar como allowed
    const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'new-group-alias@g.us'`).get() as any;
    expect(row && String(row.status)).toBe('allowed');
  });

  test('admin puede deshabilitar el grupo actual con alias /admin disable', async () => {
    const payload = {
      event: 'messages.upsert',
      instance: 'test-instance',
      data: {
        key: {
          remoteJid: 'disable-group@g.us',
          participant: '1234567890@s.whatsapp.net'
        },
        message: { conversation: '/admin disable' }
      }
    };

    const res = await WebhookServer.handleRequest(createTestRequest(payload));
    expect(res.status).toBe(200);

    expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);

    const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'disable-group@g.us'`).get() as any;
    expect(row && String(row.status)).toBe('blocked');
  });

  test('admin puede permitir un grupo por JID con alias /admin allow <jid>', async () => {
    const payload = {
      event: 'messages.upsert',
      instance: 'test-instance',
      data: {
        key: {
          remoteJid: 'some-group@g.us',
          participant: '1234567890@s.whatsapp.net'
        },
        message: { conversation: '/admin allow target-allow@g.us' }
      }
    };

    const res = await WebhookServer.handleRequest(createTestRequest(payload));
    expect(res.status).toBe(200);

    const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'target-allow@g.us'`).get() as any;
    expect(row && String(row.status)).toBe('allowed');
  });

  test('admin puede bloquear un grupo por JID con alias /admin block <jid>', async () => {
    const payload = {
      event: 'messages.upsert',
      instance: 'test-instance',
      data: {
        key: {
          remoteJid: 'some-group@g.us',
          participant: '1234567890@s.whatsapp.net'
        },
        message: { conversation: '/admin block target-block@g.us' }
      }
    };

    const res = await WebhookServer.handleRequest(createTestRequest(payload));
    expect(res.status).toBe(200);

    const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'target-block@g.us'`).get() as any;
    expect(row && String(row.status)).toBe('blocked');
  });

  test('admin puede ver pendientes con alias /admin pending', async () => {
    const payload = {
      event: 'messages.upsert',
      instance: 'test-instance',
      data: {
        key: {
          remoteJid: 'some-group@g.us',
          participant: '1234567890@s.whatsapp.net'
        },
        message: { conversation: '/admin pending' }
      }
    };

    const res = await WebhookServer.handleRequest(createTestRequest(payload));
    expect(res.status).toBe(200);

    const out = SimulatedResponseQueue.get();
    expect(out.length).toBe(1);
    expect(String(out[0].message).toLowerCase()).toContain('no hay grupos pendientes');
  });
});
