import { t } from 'elysia';
import { createRouter } from '$shared/utils/ws-server';
import {
	listUsers,
	removeUser,
	listUserProjects,
	assignProjectToUser,
	unassignProjectFromUser
} from '$backend/auth/auth-service';
import { invalidateUserSessions } from '$backend/auth/session-invalidation';
import { auditLogQueries } from '$backend/database/queries';
import { ws } from '$backend/utils/ws';
import { clientIpFromConnection } from '$backend/utils/client-ip';

export const usersHandler = createRouter()
	// List all users (admin only — enforced by auth gate)
	.http('auth:list-users', {
		data: t.Object({}),
		response: t.Array(t.Object({
			id: t.String(),
			name: t.String(),
			role: t.Union([t.Literal('admin'), t.Literal('member')]),
			color: t.String(),
			avatar: t.String(),
			createdAt: t.String()
		}))
	}, async () => {
		return listUsers();
	})

	// Remove user (admin only)
	.http('auth:remove-user', {
		data: t.Object({
			userId: t.String({ minLength: 1 })
		}),
		response: t.Object({
			success: t.Boolean()
		})
	}, async ({ data }) => {
		removeUser(data.userId);
		ws.emit.global('auth:users-changed', { type: 'removed', userId: data.userId });
		return { success: true };
	})

	// List projects assigned to a specific user (admin only)
	.http('auth:list-user-projects', {
		data: t.Object({
			userId: t.String({ minLength: 1 })
		}),
		response: t.Array(t.Any())
	}, async ({ data }) => {
		return listUserProjects(data.userId);
	})

	// Assign a project to a user (admin only)
	.http('auth:assign-project', {
		data: t.Object({
			userId: t.String({ minLength: 1 }),
			projectId: t.String({ minLength: 1 })
		}),
		response: t.Object({
			added: t.Boolean()
		})
	}, async ({ data, conn }) => {
		const actorUserId = ws.getUserId(conn);
		const added = assignProjectToUser(data.userId, data.projectId);
		if (added) {
			auditLogQueries.logEvent({
				userId: data.userId,
				actorUserId,
				eventType: 'project:assigned',
				eventDetails: `Project ${data.projectId} assigned to user ${data.userId}`,
				ipAddress: clientIpFromConnection(conn)
			});
			ws.emit.global('auth:user-projects-changed', {
				type: 'assigned',
				userId: data.userId,
				projectId: data.projectId
			});
		}
		return { added };
	})

	// Revoke a user's access to a project (admin only)
	.http('auth:unassign-project', {
		data: t.Object({
			userId: t.String({ minLength: 1 }),
			projectId: t.String({ minLength: 1 })
		}),
		response: t.Object({
			removed: t.Boolean()
		})
	}, async ({ data, conn }) => {
		const actorUserId = ws.getUserId(conn);
		const removed = unassignProjectFromUser(data.userId, data.projectId);
		if (removed) {
			invalidateUserSessions(data.userId, data.projectId);
			auditLogQueries.logEvent({
				userId: data.userId,
				actorUserId,
				eventType: 'project:unassigned',
				eventDetails: `Project ${data.projectId} unassigned from user ${data.userId}`,
				ipAddress: clientIpFromConnection(conn)
			});
			ws.emit.global('auth:user-projects-changed', {
				type: 'unassigned',
				userId: data.userId,
				projectId: data.projectId
			});
		}
		return { removed };
	});
