// SPDX-License-Identifier: AGPL-3.0-or-later

import {beforeEach, describe, test} from 'vitest';
import {createTestAccount, setUserACLs} from '../../auth/tests/AuthTestUtils';
import {type ApiTestHarness, createApiTestHarness} from '../../test/ApiTestHarness';
import {HTTP_STATUS} from '../../test/TestConstants';
import {createBuilder, createBuilderWithoutAuth} from '../../test/TestRequestBuilder';

describe('Security Access Control', () => {
	let harness: ApiTestHarness;
	beforeEach(async () => {
		harness = await createApiTestHarness();
	});
	describe('Blocked User Restrictions', () => {
		test('blocked user cannot send friend request', async () => {
			const user1 = await createTestAccount(harness);
			const user2 = await createTestAccount(harness);
			await createBuilder(harness, `${user1.token}`)
				.put(`/users/@me/relationships/${user2.userId}`)
				.body({
					type: 2,
				})
				.expect(HTTP_STATUS.OK)
				.execute();
			await createBuilder(harness, `${user2.token}`)
				.post(`/users/@me/relationships/${user1.userId}`)
				.body(null)
				.expect(HTTP_STATUS.BAD_REQUEST)
				.execute();
		});
		test('blocked user cannot create DM', async () => {
			const user1 = await createTestAccount(harness);
			const user2 = await createTestAccount(harness);
			await createBuilder(harness, `${user1.token}`)
				.put(`/users/@me/relationships/${user2.userId}`)
				.body({
					type: 2,
				})
				.execute();
			await createBuilder(harness, `${user2.token}`)
				.post('/users/@me/channels')
				.body({
					recipients: [user1.userId],
				})
				.expect(HTTP_STATUS.BAD_REQUEST, 'GROUP_DM_RECIPIENTS_NOT_ADDABLE')
				.execute();
		});
	});
	describe('Unauthorized Access', () => {
		test('unauthorized user cannot access other users @me endpoint', async () => {
			const user1 = await createTestAccount(harness);
			await createTestAccount(harness);
			await createBuilder(harness, `${user1.token}`).get('/users/@me').expect(HTTP_STATUS.OK).execute();
		});
		test('unauthorized access without token is rejected', async () => {
			await createBuilderWithoutAuth(harness).get('/users/@me').expect(HTTP_STATUS.UNAUTHORIZED).execute();
		});
		test('unauthorized access with invalid token is rejected', async () => {
			await createBuilder(harness, 'Bearer invalid_token_12345')
				.get('/users/@me')
				.expect(HTTP_STATUS.UNAUTHORIZED)
				.execute();
		});
		test('unauthorized guild access is rejected', async () => {
			const owner = await createTestAccount(harness);
			const attacker = await createTestAccount(harness);
			const createJson = await createBuilder<{
				id: string;
			}>(harness, `${owner.token}`)
				.post('/guilds')
				.body({
					name: 'Private Guild',
				})
				.expect(HTTP_STATUS.OK)
				.execute();
			const guildId = createJson.id;
			await createBuilder(harness, `${attacker.token}`)
				.get(`/guilds/${guildId}`)
				.expect(HTTP_STATUS.FORBIDDEN, 'ACCESS_DENIED')
				.execute();
		});
		test('unauthorized channel access is rejected', async () => {
			const owner = await createTestAccount(harness);
			const attacker = await createTestAccount(harness);
			const createJson = await createBuilder<{
				id: string;
			}>(harness, `${owner.token}`)
				.post('/guilds')
				.body({
					name: 'Private Guild',
				})
				.expect(HTTP_STATUS.OK)
				.execute();
			const guildId = createJson.id;
			await createBuilder(harness, `${attacker.token}`)
				.get(`/guilds/${guildId}/channels`)
				.expect(HTTP_STATUS.NOT_FOUND, 'UNKNOWN_GUILD')
				.execute();
		});
	});
	describe('Admin Endpoint Security', () => {
		test('admin endpoints require admin authentication', async () => {
			const regularUser = await createTestAccount(harness);
			await createBuilder(harness, `${regularUser.token}`)
				.post('/admin/users/lookup')
				.body({
					user_ids: [regularUser.userId],
				})
				.expect(HTTP_STATUS.FORBIDDEN)
				.execute();
		});
		test('admin endpoints require proper ACLs', async () => {
			const admin = await createTestAccount(harness);
			await setUserACLs(harness, admin, ['admin:authenticate']);
			await createBuilder(harness, `${admin.token}`)
				.post('/admin/users/lookup')
				.body({
					user_ids: [admin.userId],
				})
				.expect(HTTP_STATUS.FORBIDDEN)
				.execute();
		});
		test('admin endpoints succeed with proper ACLs', async () => {
			const admin = await createTestAccount(harness);
			await setUserACLs(harness, admin, ['admin:authenticate', 'user:lookup']);
			await createBuilder(harness, `${admin.token}`)
				.post('/admin/users/lookup')
				.body({
					user_ids: [admin.userId],
				})
				.expect(HTTP_STATUS.OK)
				.execute();
		});
	});
	describe('Token Security', () => {
		test('token must have valid format', async () => {
			await createBuilder(harness, 'Bearer invalid_format')
				.get('/users/@me')
				.expect(HTTP_STATUS.UNAUTHORIZED)
				.execute();
		});
		test('empty token is rejected', async () => {
			await createBuilder(harness, 'Bearer ').get('/users/@me').expect(HTTP_STATUS.UNAUTHORIZED).execute();
		});
		test('malformed token is rejected', async () => {
			await createBuilder(harness, 'Bearer flx_invalid_token_format')
				.get('/users/@me')
				.expect(HTTP_STATUS.UNAUTHORIZED)
				.execute();
		});
	});
});
