import request from 'supertest';
import { describe, it, expect, beforeAll, afterAll, jest } from '@jest/globals';
import { Express } from 'express';
import { startTestServer, stopTestServer } from '../../../utils/server-setup.js';
import { Room } from 'livekit-server-sdk';
import { container } from '../../../../src/config/dependency-injector.config.js';
import { LiveKitService } from '../../../../src/services/livekit.service.js';
import { LoggerService } from '../../../../src/services/logger.service.js';

const apiVersion = 'v1';
const baseUrl = `/meet/api/`;
const endpoint = '/rooms';

describe('Room Request Validation Tests', () => {
	let app: Express;

	beforeAll(async () => {
		app = await startTestServer();
	});

	afterAll(async () => {
		await stopTestServer();
	});

	it('✅ Should create a room with only required fields', async () => {
		const response = await request(app)
			.post(`${baseUrl}${apiVersion}${endpoint}`)
			.send({
				expirationDate: 1772129829000
			})
			.expect(200);

		expect(response.body).toHaveProperty('creationDate');
		expect(response.body).toHaveProperty('expirationDate');
		expect(response.body).toHaveProperty('maxParticipants');
		expect(response.body).toHaveProperty('preferences');
		expect(response.body).toHaveProperty('moderatorRoomUrl');
		expect(response.body).toHaveProperty('publisherRoomUrl');
		expect(response.body).toHaveProperty('viewerRoomUrl');
		expect(response.body).not.toHaveProperty('permissions');
	});

	it('✅ Should create a room with full attributes', async () => {
		const response = await request(app)
			.post(`${baseUrl}${apiVersion}${endpoint}`)
			.send({
				expirationDate: 1772129829000,
				roomNamePrefix: 'Conference',
				maxParticipants: 10,
				preferences: {
					recordingPreferences: { enabled: true },
					chatPreferences: { enabled: false },
					virtualBackgroundPreferences: { enabled: true }
				}
			})
			.expect(200);

		expect(response.body).toHaveProperty('creationDate');
		expect(response.body).toHaveProperty('expirationDate');
		expect(response.body).toHaveProperty('maxParticipants');
		expect(response.body).toHaveProperty('preferences');
		expect(response.body).toHaveProperty('moderatorRoomUrl');
		expect(response.body).toHaveProperty('publisherRoomUrl');
		expect(response.body).toHaveProperty('viewerRoomUrl');
		expect(response.body).not.toHaveProperty('permissions');
	});

	it('✅ Should use default values for missing optional fields', async () => {
		const response = await request(app)
			.post(`${baseUrl}${apiVersion}${endpoint}`)
			.send({
				expirationDate: 1772129829000
			})
			.expect(200);

		expect(response.body).toHaveProperty('preferences');
		expect(response.body.preferences).toEqual({
			recordingPreferences: { enabled: true },
¡			chatPreferences: { enabled: true },
			virtualBackgroundPreferences: { enabled: true }
		});
	});

	it('❌ Should return 422 when missing expirationDate', async () => {
		const response = await request(app).post(`${baseUrl}${apiVersion}${endpoint}`).send({}).expect(422);

		expect(response.body).toHaveProperty('error', 'Unprocessable Entity');
		expect(response.body.details[0].field).toBe('expirationDate');
		expect(response.body.details[0].message).toContain('Required');
	});

	it('❌ Should return 422 when expirationDate is in the past', async () => {
		const response = await request(app)
			.post(`${baseUrl}${apiVersion}${endpoint}`)
			.send({
				expirationDate: 1600000000000
			})
			.expect(422);

		expect(response.body.details[0].message).toContain('Expiration date must be in the future');
	});

	it('❌ Should return 422 when maxParticipants is negative', async () => {
		const response = await request(app)
			.post(`${baseUrl}${apiVersion}${endpoint}`)
			.send({
				expirationDate: 1772129829000,
				maxParticipants: -5
			})
			.expect(422);

		expect(response.body.details[0].field).toBe('maxParticipants');
		expect(response.body.details[0].message).toContain('Max participants must be a positive integer');
	});

	it('❌ Should return 422 when maxParticipants is not a number', async () => {
		const response = await request(app)
			.post(`${baseUrl}${apiVersion}${endpoint}`)
			.send({
				expirationDate: 1772129829000,
				maxParticipants: 'ten'
			})
			.expect(422);

		expect(response.body.details[0].message).toContain('Expected number, received string');
	});

	it('❌ Should return 422 when expirationDate is not a number', async () => {
		const response = await request(app)
			.post(`${baseUrl}${apiVersion}${endpoint}`)
			.send({
				expirationDate: 'tomorrow'
			})
			.expect(422);

		expect(response.body.details[0].message).toContain('Expected number, received string');
	});

	it('❌ Should return 422 when preferences contain wrong types', async () => {
		const response = await request(app)
			.post(`${baseUrl}${apiVersion}${endpoint}`)
			.send({
				expirationDate: 1772129829000,
				preferences: {
					recordingPreferences: { enabled: 'yes' },
					chatPreferences: { enabled: 'no' }
				}
			})
			.expect(422);

		expect(response.body.details[0].message).toContain('Expected boolean, received string');
	});

	it('❌ Should return 500 when an internal server error occurs', async () => {
		jest.mock('../../../../src/services/livekit.service');
		jest.mock('../../../../src/services/logger.service');

		const mockLiveKitService = container.get(LiveKitService);
		mockLiveKitService.createRoom = jest.fn<() => Promise<Room>>().mockRejectedValue(new Error('LiveKit Error'));

		const mockLoggerService = container.get(LoggerService);
		mockLoggerService.error = jest.fn();

		const response = await request(app).post(`${baseUrl}${apiVersion}${endpoint}`).send({
			expirationDate: 1772129829000,
			roomNamePrefix: 'OpenVidu'
		});

		expect(response.status).toBe(500);
		expect(response.body.message).toContain('Internal server error');
	});
});
