import { supabase } from '../../supabaseClient'; import { CCUser, convertToCCUser } from '../../services/auth/authService'; import { EmailCredentials } from '../../services/auth/authService'; import { formatEmailForDatabase } from '../graph/neoDBService'; import { RegistrationResponse } from '../../services/auth/authService'; import { storageService, StorageKeys } from './localStorageService'; import { logger } from '../../debugConfig'; import { provisionUser } from '../provisioningService'; const REGISTRATION_SERVICE = 'registration-service'; export class RegistrationService { private static instance: RegistrationService; private constructor() {} static getInstance(): RegistrationService { if (!RegistrationService.instance) { RegistrationService.instance = new RegistrationService(); } return RegistrationService.instance; } async register(credentials: EmailCredentials, displayName: string): Promise { try { logger.debug(REGISTRATION_SERVICE, '🔄 Starting registration', { email: credentials.email, role: credentials.role, hasDisplayName: !!displayName }); // Generate username from email (or use another method) const username = formatEmailForDatabase(credentials.email); // 1. First sign up the user in auth const { data: authData, error: signUpError } = await supabase.auth.signUp({ email: credentials.email, password: credentials.password, options: { data: { user_type: credentials.role, username: username, display_name: displayName } } }); if (signUpError) { logger.error(REGISTRATION_SERVICE, '❌ Supabase signup error', { error: signUpError }); throw signUpError; } if (!authData.user) { logger.error(REGISTRATION_SERVICE, '❌ No user data after registration'); throw new Error('No user data after registration'); } const ccUser: CCUser = convertToCCUser(authData.user, authData.user.user_metadata); // 2. Update the profile with the correct user type const { error: updateError } = await supabase .from('profiles') .update({ user_type: credentials.role, username: username, display_name: displayName }) .eq('id', authData.user.id) .select() .single(); if (updateError) { logger.error(REGISTRATION_SERVICE, '❌ Failed to update profile', updateError); throw updateError; } storageService.set(StorageKeys.IS_NEW_REGISTRATION, true); let provisioningToken = authData.session?.access_token || null; if (!provisioningToken) { const { data: sessionData } = await supabase.auth.getSession(); provisioningToken = sessionData.session?.access_token || null; } // 3. Create Neo4j nodes try { const provisioned = await provisionUser(ccUser.id, provisioningToken); if (provisioned) { logger.info(REGISTRATION_SERVICE, '✅ Provisioning successful', { userId: ccUser.id, userDbName: provisioned.user_db_name, workerDbName: provisioned.worker_db_name }); } else { logger.warn(REGISTRATION_SERVICE, '⚠️ Provisioning skipped or pending', { userId: ccUser.id }); } } catch (provisionError) { logger.warn(REGISTRATION_SERVICE, '⚠️ Provisioning error', { userId: ccUser.id, error: provisionError }); } return { user: ccUser, accessToken: authData.session?.access_token || null, userRole: credentials.role, message: 'Registration successful' }; } catch (error) { logger.error(REGISTRATION_SERVICE, '❌ Registration failed:', error); throw error; } } } export const registrationService = RegistrationService.getInstance();