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

let originalAdd: any;

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

// Test database instance
let testDb: Database;

beforeAll(() => {
	// Create in-memory test database
	testDb = new Database(':memory:');
	// Initialize schema
	initializeDatabase(testDb);
	// Guardar implementación original de ResponseQueue.add para restaurar después
	originalAdd = (ResponseQueue as any).add;
});

afterAll(() => {
	(ResponseQueue as any).add = originalAdd;
	// Close the test database
	testDb.close();
});

beforeEach(() => {
	// Clear simulated queue
	SimulatedResponseQueue.clear();

	// Replace ResponseQueue with simulated version
	(ResponseQueue as any).add = SimulatedResponseQueue.add;

	// Inject testDb for WebhookServer to use
	WebhookServer.dbInstance = testDb;

	// Usar el locator global para el resto de servicios
	setDb(testDb);

	// Ensure database is initialized (recreates tables if dropped)
	initializeDatabase(testDb);

	// Reset database state between tests (borrar raíz primero; ON DELETE CASCADE limpia assignments)
	testDb.exec('DELETE FROM response_queue');
	try { testDb.exec('DELETE FROM task_origins'); } catch { }
	testDb.exec('DELETE FROM tasks');
	testDb.exec('DELETE FROM users');
	testDb.exec('DELETE FROM groups');

	// Insert test data for active group
	testDb.exec(`
    INSERT OR IGNORE INTO groups (id, community_id, name, active)
    VALUES ('group-id@g.us', 'test-community', 'Test Group', 1)
  `);

	// Populate active groups cache with test data
	GroupSyncService['cacheActiveGroups']();
});

describe('WebhookServer', () => {
	const envBackup = process.env;

	beforeEach(() => {
		process.env = {
			...envBackup,
			INSTANCE_NAME: 'test-instance',
			NODE_ENV: 'test'
		};
	});

	afterEach(() => {
		process.env = envBackup;
		(ResponseQueue as any).add = originalAdd;
	});

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

	test('should reject non-POST requests', async () => {
		const request = new Request('http://localhost:3007', { method: 'GET' });
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(405);
	});

	test('should require JSON content type', async () => {
		const request = new Request('http://localhost:3007', {
			method: 'POST',
			headers: { 'Content-Type': 'text/plain' }
		});
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(400);
	});

	test('should validate payload structure', async () => {
		const invalidPayloads = [
			{},
			{ event: null },
			{ event: 'messages.upsert', instance: null }
		];

		for (const invalidPayload of invalidPayloads) {
			const request = createTestRequest(invalidPayload);
			const response = await WebhookServer.handleRequest(request);
			expect(response.status).toBe(400);
		}
	});

	test('should verify instance name', async () => {
		process.env.TEST_VERIFY_INSTANCE = 'true';
		const payload = {
			event: 'messages.upsert',
			instance: 'wrong-instance',
			data: {}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(403);
		delete process.env.TEST_VERIFY_INSTANCE;
	});

	test('should handle valid messages.upsert', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: '/tarea nueva Test' }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
	});

	test('should ignore empty message content', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: '' }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBe(0);
	});

	test('should handle very long messages', async () => {
		const longMessage = '/tarea nueva ' + 'A'.repeat(5000);
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: longMessage }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
	});

	test('should handle messages with special characters and emojis', async () => {
		const specialMessage = '/tarea nueva Test 😊 你好 @#$%^&*()';
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: specialMessage }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
	});

	test('should ignore non-/tarea commands', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: '/othercommand test' }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBe(0);
	});

	test('should ignore message with mentions but no command', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: {
					conversation: 'Hello everyone!',
					contextInfo: {
						mentionedJid: ['1234567890@s.whatsapp.net']
					}
				}
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBe(0);
	});

	test('should ignore media attachment messages', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: {
					imageMessage: { caption: 'This is an image' }
				}
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBe(0);
	});

	test('should process command from extendedTextMessage', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: {
					extendedTextMessage: { text: '/t n Test ext' }
				}
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
	});

	test('should process command from image caption when caption starts with a command', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: {
					imageMessage: { caption: '/t n From caption' }
				}
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
	});

	test('should handle requests on configured port', async () => {
		const originalPort = process.env.PORT;
		process.env.PORT = '3007';
		// Satisfacer validación de entorno en start()
		const prevEnv = {
			EVOLUTION_API_URL: process.env.EVOLUTION_API_URL,
			EVOLUTION_API_KEY: process.env.EVOLUTION_API_KEY,
			EVOLUTION_API_INSTANCE: process.env.EVOLUTION_API_INSTANCE,
			CHATBOT_PHONE_NUMBER: process.env.CHATBOT_PHONE_NUMBER,
			WEBHOOK_URL: process.env.WEBHOOK_URL
		};
		process.env.EVOLUTION_API_URL = 'http://localhost:3000';
		process.env.EVOLUTION_API_KEY = 'test-key';
		process.env.EVOLUTION_API_INSTANCE = 'test-instance';
		process.env.CHATBOT_PHONE_NUMBER = '9999999999';
		process.env.WEBHOOK_URL = 'http://localhost:3007';

		try {
			const server = await WebhookServer.start();
			const response = await fetch('http://localhost:3007/health');
			expect(response.status).toBe(200);
			server.stop();
		} finally {
			process.env.PORT = originalPort;
			process.env.EVOLUTION_API_URL = prevEnv.EVOLUTION_API_URL;
			process.env.EVOLUTION_API_KEY = prevEnv.EVOLUTION_API_KEY;
			process.env.EVOLUTION_API_INSTANCE = prevEnv.EVOLUTION_API_INSTANCE;
			process.env.CHATBOT_PHONE_NUMBER = prevEnv.CHATBOT_PHONE_NUMBER;
			process.env.WEBHOOK_URL = prevEnv.WEBHOOK_URL;
		}
	});

	function getFutureDate(days: number): string {
		const date = new Date();
		date.setDate(date.getDate() + days);
		return date.toISOString().split('T')[0];
	}

	describe('/tarea command logging', () => {
		test('should log basic /tarea command', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: 'user123@s.whatsapp.net'
					},
					message: { conversation: '/tarea test' }
				}
			};

			await WebhookServer.handleRequest(createTestRequest(payload));

			// Check that a response was queued (indicating command processing)
			expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
		});

		test('should log command with due date', async () => {
			const futureDate = getFutureDate(3); // Get date 3 days in future
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: 'user123@s.whatsapp.net'
					},
					message: {
						conversation: `/tarea nueva Finish project @user2 ${futureDate}`,
						contextInfo: {
							mentionedJid: ['user2@s.whatsapp.net']
						}
					}
				}
			};

			await WebhookServer.handleRequest(createTestRequest(payload));

			// Verify command processing by checking queue
			expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
		});
	});

	test('should handle XSS/SQL injection attempts', async () => {
		const maliciousMessage = `/tarea nueva <script>alert('xss')</script>'; DROP TABLE tasks; --`;
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: maliciousMessage }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
	});

	test('should handle multiple dates in command (use last one as due date)', async () => {
		const futureDate1 = getFutureDate(3);
		const futureDate2 = getFutureDate(5);
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: `/tarea nueva Test task ${futureDate1} some text ${futureDate2}` }
			}
		};

		await WebhookServer.handleRequest(createTestRequest(payload));

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

	test('should ignore past dates as due dates', async () => {
		const pastDate = '2020-01-01';
		const futureDate = getFutureDate(2);
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: `/tarea nueva Test task ${pastDate} more text ${futureDate}` }
			}
		};

		await WebhookServer.handleRequest(createTestRequest(payload));

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

	test('should handle multiple past dates correctly', async () => {
		const pastDate1 = '2020-01-01';
		const pastDate2 = '2021-01-01';
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: `/tarea nueva Test task ${pastDate1} and ${pastDate2}` }
			}
		};

		await WebhookServer.handleRequest(createTestRequest(payload));

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

	test('should handle mixed valid and invalid date formats', async () => {
		const futureDate = getFutureDate(2);
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'sender-id@s.whatsapp.net'
				},
				message: { conversation: `/tarea nueva Test task 2023-13-01 (invalid) ${futureDate} 25/12/2023 (invalid)` }
			}
		};

		await WebhookServer.handleRequest(createTestRequest(payload));

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

	test('should normalize sender ID before processing', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: '1234567890:12@s.whatsapp.net' // ID with participant
				},
				message: { conversation: '/tarea nueva Test' }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
	});

	test('should ignore messages with invalid sender ID', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: 'invalid-id!' // Invalid ID
				},
				message: { conversation: '/tarea nueva Test' }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBe(0);
	});

	test('should ensure user exists and use normalized ID', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: '1234567890@s.whatsapp.net'
				},
				message: { conversation: '/tarea nueva Test' }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);

		// Verify user was created in real database
		const user = testDb.query("SELECT * FROM users WHERE id = ?").get('1234567890');
		expect(user).toBeDefined();
		expect(user.id).toBe('1234567890');
	});

	test('should ignore messages if user creation fails', async () => {
		const payload = {
			event: 'messages.upsert',
			instance: 'test-instance',
			data: {
				key: {
					remoteJid: 'group-id@g.us',
					participant: null // Invalid participant
				},
				message: { conversation: '/tarea nueva Test' }
			}
		};
		const request = createTestRequest(payload);
		const response = await WebhookServer.handleRequest(request);
		expect(response.status).toBe(200);
		expect(SimulatedResponseQueue.get().length).toBe(0);

		// Verify no user was created
		const userCount = testDb.query("SELECT COUNT(*) as count FROM users").get();
		expect(userCount.count).toBe(0);
	});

	// Integration tests with real database
	describe('User validation in handleMessageUpsert', () => {
		test('should proceed with valid user', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/tarea nueva Test' }
				}
			};
			const request = createTestRequest(payload);
			const response = await WebhookServer.handleRequest(request);
			expect(response.status).toBe(200);
			expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);

			// Verify user was created in real database
			const user = testDb.query("SELECT * FROM users WHERE id = ?").get('1234567890');
			expect(user).toBeDefined();
			expect(user.id).toBe('1234567890');
		});

		test('should ignore message if user validation fails', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: 'invalid!user@s.whatsapp.net'
					},
					message: { conversation: '/tarea nueva Test' }
				}
			};
			const request = createTestRequest(payload);
			const response = await WebhookServer.handleRequest(request);
			expect(response.status).toBe(200);
			expect(SimulatedResponseQueue.get().length).toBe(0);

			// Verify no user was created
			const userCount = testDb.query("SELECT COUNT(*) as count FROM users").get();
			expect(userCount.count).toBe(0);
		});

		test('should handle database errors during user validation', async () => {
			// Force a database error by corrupting the database state
			testDb.exec('DROP TABLE users');

			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/tarea nueva Test' }
				}
			};
			const request = createTestRequest(payload);
			const response = await WebhookServer.handleRequest(request);
			expect(response.status).toBe(200);
			expect(SimulatedResponseQueue.get().length).toBe(0);

			// Reinitialize database for subsequent tests (force full migration)
			testDb.exec('DROP TABLE IF EXISTS schema_migrations');
			initializeDatabase(testDb);
		});

		test('should integrate user validation completely in handleMessageUpsert with valid user', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/tarea nueva Test' }
				}
			};
			const request = createTestRequest(payload);
			const response = await WebhookServer.handleRequest(request);
			expect(response.status).toBe(200);
			expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);

			// Verify user was created/updated in database
			const user = testDb.query("SELECT * FROM users WHERE id = ?").get('1234567890');
			expect(user).toBeDefined();
			expect(user.id).toBe('1234567890');
			expect(user.first_seen).toBeDefined();
			expect(user.last_seen).toBeDefined();
		});

		test('should use normalized ID in command service', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890:12@s.whatsapp.net' // Raw ID with participant
					},
					message: { conversation: '/tarea nueva Test' }
				}
			};

			const request = createTestRequest(payload);
			await WebhookServer.handleRequest(request);

			// Verify that a response was queued, indicating command processing
			expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
		});

		test('should handle end-to-end flow with valid user and command processing', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/tarea nueva Test task' }
				}
			};

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

			// Verify user was created/updated
			const user = testDb.query("SELECT * FROM users WHERE id = ?").get('1234567890');
			expect(user).toBeDefined();

			// Verify that a response was queued
			expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
		});
	});

	describe('Group validation in handleMessageUpsert', () => {
		test('should ignore messages from inactive groups', async () => {
			// Insert inactive group
			testDb.exec(`
        INSERT OR REPLACE INTO groups (id, community_id, name, active)
        VALUES ('inactive-group@g.us', 'test-community', 'Inactive Group', 0)
      `);

			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'inactive-group@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/tarea nueva Test' }
				}
			};
			const request = createTestRequest(payload);
			const response = await WebhookServer.handleRequest(request);
			expect(response.status).toBe(200);
			expect(SimulatedResponseQueue.get().length).toBe(0);
		});

		test('should proceed with messages from active groups', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/tarea nueva Test' }
				}
			};
			const request = createTestRequest(payload);
			const response = await WebhookServer.handleRequest(request);
			expect(response.status).toBe(200);
			expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
		});

		test('should accept /t alias and process command', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/t n Tarea alias hoy' }
				}
			};
			const request = createTestRequest(payload);
			const response = await WebhookServer.handleRequest(request);
			expect(response.status).toBe(200);
			expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
		});

		test('should never send responses to the group (DM only policy)', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/t n Probar silencio grupo mañana' }
				}
			};
			const request = createTestRequest(payload);
			await WebhookServer.handleRequest(request);

			const out = SimulatedResponseQueue.get();
			expect(out.length).toBeGreaterThan(0);
			for (const r of out) {
				expect(r.recipient.endsWith('@g.us')).toBe(false);
			}
		});
	});

	describe('Advanced listings via WebhookServer', () => {
		test('should process "/t ver sin" in group as DM-only with pagination line', async () => {
			// 12 sin dueño en el grupo activo
			for (let i = 1; i <= 12; i++) {
				TaskService.createTask({
					description: `Sin dueño ${i}`,
					due_date: '2025-12-31',
					group_id: 'group-id@g.us',
					created_by: '9999999999',
				});
			}
			// 2 asignadas (no deben aparecer en "sin")
			TaskService.createTask({
				description: 'Asignada 1',
				due_date: '2025-10-10',
				group_id: 'group-id@g.us',
				created_by: '1111111111',
			}, [{ user_id: '1234567890', assigned_by: '1111111111' }]);

			TaskService.createTask({
				description: 'Asignada 2',
				due_date: '2025-10-11',
				group_id: 'group-id@g.us',
				created_by: '1111111111',
			}, [{ user_id: '1234567890', assigned_by: '1111111111' }]);

			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/t ver sin' }
				}
			};
			const response = await WebhookServer.handleRequest(createTestRequest(payload));
			expect(response.status).toBe(200);

			const out = SimulatedResponseQueue.get();
			expect(out.length).toBeGreaterThan(0);
			for (const r of out) {
				expect(r.recipient.endsWith('@g.us')).toBe(false);
			}
			const msg = out.map(x => x.message).join('\n');
			expect(msg).toContain('No respondo en grupos.');
		});

		test('should process "/t ver sin" in DM returning instruction', async () => {
			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: '1234567890@s.whatsapp.net', // DM
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/t ver sin' }
				}
			};
			const response = await WebhookServer.handleRequest(createTestRequest(payload));
			expect(response.status).toBe(200);

			const out = SimulatedResponseQueue.get();
			expect(out.length).toBeGreaterThan(0);
			const msg = out.map(x => x.message).join('\n');
			expect(msg).toContain('No tienes tareas pendientes.');
		});

		test('should process "/t ver todos" in group showing "Tus tareas" + "Sin dueño (grupo actual)" with pagination in unassigned section', async () => {
			// Tus tareas (2 asignadas)
			TaskService.createTask({
				description: 'Mi Tarea 1',
				due_date: '2025-10-10',
				group_id: 'group-id@g.us',
				created_by: '2222222222',
			}, [{ user_id: '1234567890', assigned_by: '2222222222' }]);

			TaskService.createTask({
				description: 'Mi Tarea 2',
				due_date: '2025-10-11',
				group_id: 'group-id@g.us',
				created_by: '2222222222',
			}, [{ user_id: '1234567890', assigned_by: '2222222222' }]);

			// 12 sin dueño para provocar paginación
			for (let i = 1; i <= 12; i++) {
				TaskService.createTask({
					description: `Sin dueño ${i}`,
					due_date: '2025-12-31',
					group_id: 'group-id@g.us',
					created_by: '9999999999',
				});
			}

			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: 'group-id@g.us',
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/t ver todos' }
				}
			};
			const response = await WebhookServer.handleRequest(createTestRequest(payload));
			expect(response.status).toBe(200);

			const out = SimulatedResponseQueue.get();
			expect(out.length).toBeGreaterThan(0);
			const msg = out.map(x => x.message).join('\n');
			expect(msg).toContain('No respondo en grupos.');
		});

		test('should process "/t ver todos" in DM showing "Tus tareas" + instructive note', async () => {
			TaskService.createTask({
				description: 'Mi Tarea A',
				due_date: '2025-11-20',
				group_id: 'group-2@g.us',
				created_by: '1111111111',
			}, [{ user_id: '1234567890', assigned_by: '1111111111' }]);

			const payload = {
				event: 'messages.upsert',
				instance: 'test-instance',
				data: {
					key: {
						remoteJid: '1234567890@s.whatsapp.net', // DM
						participant: '1234567890@s.whatsapp.net'
					},
					message: { conversation: '/t ver todos' }
				}
			};
			const response = await WebhookServer.handleRequest(createTestRequest(payload));
			expect(response.status).toBe(200);

			const out = SimulatedResponseQueue.get();
			expect(out.length).toBeGreaterThan(0);
			const msg = out.map(x => x.message).join('\n');
			expect(msg).toContain('Tus tareas');
			expect(msg).toContain('ℹ️ Para ver tareas sin responsable');
		});
	});
});
