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

import type {GuildResponse} from '@fluxer/schema/src/domains/guild/GuildResponseSchemas';
import {afterAll, beforeAll, beforeEach, describe, expect, it} from 'vitest';
import {setInjectedRegistrationRiskEvaluator} from '../../middleware/ServiceMiddleware';
import {
	RecommendedAction,
	RiskConfidence,
	RiskDecisionMethod,
	RiskLevel,
	type RiskLevel as RiskLevelType,
} from '../../risk/RiskTypes';
import type {ApiTestHarness} from '../../test/ApiTestHarness';
import {createBuilder, createBuilderWithoutAuth} from '../../test/TestRequestBuilder';
import type {IRegistrationRiskEvaluator} from '../services/IRegistrationRiskEvaluator';
import {
	createAuthHarness,
	createTestAccount,
	createUniqueEmail,
	createUniqueUsername,
	loginAccount,
	registerUser,
} from './AuthTestUtils';

function createStaticRiskEvaluator(params: {
	level: RiskLevelType;
	riskScore: number;
	recommendedAction: RecommendedAction;
}): IRegistrationRiskEvaluator {
	return {
		async evaluate() {
			return {
				level: params.level,
				recommendedAction: params.recommendedAction,
				assessment: {
					suspicious: params.level !== RiskLevel.Low,
					level: params.level,
					confidence: RiskConfidence.High,
					riskScore: params.riskScore,
					reasoning: 'test risk verdict',
					recommendedAction: params.recommendedAction,
					method: RiskDecisionMethod.Noop,
					modelUsed: 'test',
					rounds: 0,
					elapsedMs: 0,
					signals: {},
				},
			};
		},
	};
}

async function createGuildInvite(harness: ApiTestHarness): Promise<{
	guildId: string;
	inviteCode: string;
	ownerToken: string;
}> {
	let owner = await createTestAccount(harness);
	await createBuilderWithoutAuth(harness)
		.post(`/test/users/${owner.userId}/acls`)
		.body({
			acls: ['*'],
		})
		.expect(200)
		.execute();
	owner = await loginAccount(harness, owner);
	const guild = await createBuilder<GuildResponse>(harness, owner.token)
		.post('/guilds')
		.body({
			name: `InviteGuild-${Date.now()}`,
		})
		.execute();
	if (!guild.system_channel_id) {
		throw new Error('Guild creation did not return a system_channel_id');
	}
	const invite = await createBuilder<{
		code: string;
	}>(harness, owner.token)
		.post(`/channels/${guild.system_channel_id}/invites`)
		.body({
			max_uses: 0,
			max_age: 0,
			unique: false,
			temporary: false,
		})
		.execute();
	return {guildId: guild.id, inviteCode: invite.code, ownerToken: owner.token};
}

describe('Auth registration invite auto-join risk gating', () => {
	let harness: ApiTestHarness;
	beforeAll(async () => {
		harness = await createAuthHarness();
	});
	beforeEach(async () => {
		setInjectedRegistrationRiskEvaluator(undefined);
		await harness.reset();
	});
	afterAll(async () => {
		setInjectedRegistrationRiskEvaluator(undefined);
		await harness?.shutdown();
	});
	it('auto-joins the invite on medium-risk registrations', async () => {
		const {guildId, inviteCode, ownerToken} = await createGuildInvite(harness);
		setInjectedRegistrationRiskEvaluator(
			createStaticRiskEvaluator({
				level: RiskLevel.Medium,
				riskScore: 40,
				recommendedAction: RecommendedAction.RequireVerifiedEmail,
			}),
		);
		const registration = await registerUser(harness, {
			email: createUniqueEmail('invite-medium'),
			username: createUniqueUsername('invite_medium'),
			global_name: 'Invite Medium',
			password: 'StrongPassword!123',
			date_of_birth: '2000-01-01',
			consent: true,
			invite_code: inviteCode,
		});
		const memberLookup = await createBuilder(harness, ownerToken)
			.get(`/guilds/${guildId}/members/${registration.user_id}`)
			.expect(200)
			.executeWithResponse();
		expect(memberLookup.response.status).toBe(200);
	});
	it('auto-joins the invite on high-risk registrations', async () => {
		const {guildId, inviteCode, ownerToken} = await createGuildInvite(harness);
		setInjectedRegistrationRiskEvaluator(
			createStaticRiskEvaluator({
				level: RiskLevel.High,
				riskScore: 70,
				recommendedAction: RecommendedAction.RequireOutboundPhone,
			}),
		);
		const registration = await registerUser(harness, {
			email: createUniqueEmail('invite-high'),
			username: createUniqueUsername('invite_high'),
			global_name: 'Invite High',
			password: 'StrongPassword!123',
			date_of_birth: '2000-01-01',
			consent: true,
			invite_code: inviteCode,
		});
		const memberLookup = await createBuilder(harness, ownerToken)
			.get(`/guilds/${guildId}/members/${registration.user_id}`)
			.expect(200)
			.executeWithResponse();
		expect(memberLookup.response.status).toBe(200);
	});
	it('does not auto-join the invite on very-high-risk registrations', async () => {
		const {guildId, inviteCode, ownerToken} = await createGuildInvite(harness);
		setInjectedRegistrationRiskEvaluator(
			createStaticRiskEvaluator({
				level: RiskLevel.VeryHigh,
				riskScore: 90,
				recommendedAction: RecommendedAction.RequireInboundPhone,
			}),
		);
		const registration = await registerUser(harness, {
			email: createUniqueEmail('invite-veryhigh'),
			username: createUniqueUsername('invite_veryhigh'),
			global_name: 'Invite VeryHigh',
			password: 'StrongPassword!123',
			date_of_birth: '2000-01-01',
			consent: true,
			invite_code: inviteCode,
		});
		const memberLookup = await createBuilder(harness, ownerToken)
			.get(`/guilds/${guildId}/members/${registration.user_id}`)
			.expect(404)
			.executeWithResponse();
		expect(memberLookup.response.status).toBe(404);
	});
});
