import { GraphQLError } from 'graphql';
import { ALLOWED_ROLES, invalidTokenError, mapAuth0Error } from '../helpers/invitations.helper.js';
import { AcceptInvitationsProvider } from '../providers/accept-invitations.provider.js';
import { AuthContextProvider } from '../providers/auth-context.provider.js';
import { Auth0ManagementProvider } from '../providers/auth0-management.provider.js';
import { InvitationsProvider } from '../providers/invitations.provider.js';
export const invitationsResolvers = {
    Query: {
        listInvitations: async (_, __, { injector }) => {
            try {
                return await injector.get(InvitationsProvider).listInvitations();
            }
            catch (error) {
                if (error instanceof GraphQLError) {
                    throw error;
                }
                throw new GraphQLError('Failed to list invitations', {
                    originalError: error instanceof Error ? error : undefined,
                    extensions: { code: 'INVITATION_LIST_FAILED' },
                });
            }
        },
    },
    Mutation: {
        createInvitation: async (_, { email, roleId }, { injector }) => {
            const authContext = await injector.get(AuthContextProvider).getAuthContext();
            if (!authContext?.user || !authContext.tenant?.businessId) {
                throw new GraphQLError('Authentication required', {
                    extensions: { code: 'UNAUTHENTICATED' },
                });
            }
            if (authContext.user.roleId !== 'business_owner') {
                throw new GraphQLError('Requires role: business_owner', {
                    extensions: { code: 'FORBIDDEN' },
                });
            }
            if (!ALLOWED_ROLES.has(roleId)) {
                throw new GraphQLError(`Invalid roleId: ${roleId}`, {
                    extensions: { code: 'BAD_USER_INPUT' },
                });
            }
            const normalizedEmail = email.trim().toLowerCase();
            const businessId = authContext.tenant.businessId;
            const invitedByUserId = authContext.user.userId;
            const existingInvitation = await injector
                .get(InvitationsProvider)
                .getInvitationByEmailLoader.load(normalizedEmail);
            if ((existingInvitation?.length ?? 0) > 0) {
                throw new GraphQLError('An active invitation already exists for this user', {
                    extensions: { code: 'INVITATION_ALREADY_PENDING' },
                });
            }
            let auth0UserId;
            try {
                auth0UserId = await injector
                    .get(Auth0ManagementProvider)
                    .createBlockedUser(normalizedEmail);
            }
            catch (error) {
                throw mapAuth0Error(error);
            }
            try {
                return await injector.get(InvitationsProvider).insertInvitation({
                    email: normalizedEmail,
                    roleId,
                    auth0UserId,
                    invitedByUserId,
                    ownerId: businessId,
                });
            }
            catch (error) {
                // If DB operations fail, attempt to clean up the created Auth0 user to prevent dangling resources.
                await injector
                    .get(Auth0ManagementProvider)
                    .deleteUser(auth0UserId)
                    .catch(cleanupError => {
                    console.error(`Failed to cleanup Auth0 user ${auth0UserId} after DB error:`, cleanupError);
                });
                // Re-throw the original error to ensure the GraphQL operation fails correctly.
                throw error;
            }
        },
        acceptInvitation: async (_, { token }, { injector }) => {
            const authContextProvider = injector.get(AuthContextProvider);
            const authContext = await authContextProvider.getAuthContext();
            const jwtIdentity = authContext ? null : await authContextProvider.getJwtIdentity();
            const auth0UserId = authContext?.user?.auth0UserId ?? jwtIdentity?.auth0UserId ?? null;
            const authenticatedUserEmail = authContext?.user?.email ?? jwtIdentity?.email ?? null;
            const normalizedToken = token.trim();
            if (!normalizedToken) {
                throw invalidTokenError();
            }
            try {
                return await injector
                    .get(AcceptInvitationsProvider)
                    .acceptInvitation(normalizedToken, auth0UserId, authenticatedUserEmail);
            }
            catch (error) {
                if (error instanceof GraphQLError) {
                    throw error;
                }
                throw new GraphQLError('Failed to accept invitation', {
                    extensions: { code: 'INVITATION_ACCEPT_FAILED' },
                });
            }
        },
        revokeInvitation: async (_, { id }, { injector }) => {
            try {
                return await injector.get(InvitationsProvider).revokeInvitation(id);
            }
            catch (error) {
                if (error instanceof GraphQLError) {
                    throw error;
                }
                throw new GraphQLError('Failed to revoke invitation', {
                    originalError: error instanceof Error ? error : undefined,
                    extensions: { code: 'INVITATION_REVOCATION_FAILED' },
                });
            }
        },
    },
};
//# sourceMappingURL=invitations.resolver.js.map