import readline from 'readline'; import { io } from 'socket.io-client'; const API_URL = process.env.API_URL || 'http://localhost:4010/api'; // slug المستأجر — «siro» هو المزروع على السيرفر (راجع لوق [Seed] عند الإقلاع). const TENANT_ID = process.env.TENANT_ID || 'siro'; const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const ask = (query) => new Promise((resolve) => rl.question(query, resolve)); // --- API Helpers --- async function api(method, path, body = null, token = null) { const headers = { 'Content-Type': 'application/json', 'x-tenant-id': TENANT_ID, 'x-device-id': 'simulated-device-123' }; if (token) headers['Authorization'] = `Bearer ${token}`; const options = { method, headers }; if (body) options.body = JSON.stringify(body); const res = await fetch(`${API_URL}${path}`, options); const data = await res.json().catch(() => null); if (!res.ok) { console.error(`\x1b[31m[API Error] ${method} ${path} -> ${res.status}\x1b[0m`, data); throw new Error(`API Error: ${res.status}`); } return data; } // --- Main Simulation --- async function run() { console.log('\n\x1b[36m=========================================='); console.log('🚀 Tripz Backend Live Simulation Engine'); console.log('==========================================\x1b[0m\n'); // 1. Authentication const driverPhone = await ask('📞 Enter Driver Phone Number (e.g. +962791234567): '); console.log(`[Driver] Requesting OTP for ${driverPhone}...`); await api('POST', '/auth/send-otp', { phone: driverPhone }); const driverOtp = await ask(`🔑 Enter OTP received by Driver ${driverPhone}: `); const driverAuth = await api('POST', '/auth/verify-otp', { phone: driverPhone, code: driverOtp }); const driverToken = driverAuth.access_token; console.log('\x1b[32m[Driver] Authenticated successfully!\x1b[0m'); const riderPhone = await ask('\n📞 Enter Rider Phone Number (e.g. +962781234567): '); console.log(`[Rider] Requesting OTP for ${riderPhone}...`); await api('POST', '/auth/send-otp', { phone: riderPhone }); const riderOtp = await ask(`🔑 Enter OTP received by Rider ${riderPhone}: `); const riderAuth = await api('POST', '/auth/verify-otp', { phone: riderPhone, code: riderOtp }); const riderToken = riderAuth.access_token; console.log('\x1b[32m[Rider] Authenticated successfully!\x1b[0m\n'); // 2. Setup Driver Profile & Go Online console.log(`[Driver] Creating Driver profile...`); await api('POST', '/drivers/apply', { service_class: 'economy', vehicle_make: 'Toyota', vehicle_model: 'Prius', vehicle_plate: '12-3456' }, driverToken); console.log(`[Driver] Going Online...`); await api('PATCH', '/drivers/status', { online: true }, driverToken); console.log('\x1b[32m[Driver] Profile created and is now ONLINE.\x1b[0m\n'); // 3. Connect WebSockets console.log(`[Sockets] Connecting Rider and Driver via WebSockets...`); const WS_URL = API_URL.replace('/api', ''); const driverSocket = io(WS_URL, { extraHeaders: { Authorization: `Bearer ${driverToken}` } }); const riderSocket = io(WS_URL, { extraHeaders: { Authorization: `Bearer ${riderToken}` } }); let tripId = null; driverSocket.on('connect', () => console.log('\x1b[36m[Driver WS] Connected to Gateway\x1b[0m')); riderSocket.on('connect', () => console.log('\x1b[36m[Rider WS] Connected to Gateway\x1b[0m')); driverSocket.on('trip:dispatch', async (data) => { console.log(`\n\x1b[35m[Driver WS] 🔔 RECEIVED DISPATCH for Trip ${data.id}!\x1b[0m`); tripId = data.id; console.log(`[Driver] Accepting Trip ${tripId}...`); await api('POST', `/trips/${tripId}/accept`, null, driverToken); console.log('\x1b[32m[Driver] Trip Accepted!\x1b[0m'); // Join Trip Room driverSocket.emit('trip:join', { tripId }); riderSocket.emit('trip:join', { tripId }); console.log(`[Sockets] Both joined trip room: ${tripId}\n`); }); riderSocket.on('trip:status_changed', (data) => { console.log(`\x1b[33m[Rider WS] Trip Status Changed -> ${data.status}\x1b[0m`); }); // 4. Driver Location Pings let driverLat = 32.0645; // Zarqa Coordinates let driverLng = 36.0827; const locationInterval = setInterval(() => { // Driver moves slightly driverLat += 0.0001; driverSocket.emit('driver:location', { lat: driverLat, lng: driverLng, speed: 40, heading: 90 }); console.log(`[Driver WS] 📍 Location ping: ${driverLat.toFixed(5)}, ${driverLng.toFixed(5)}`); }, 3000); // Wait a few seconds before Rider requests await new Promise(r => setTimeout(r, 5000)); // 5. Rider Requests Trip console.log(`\n[Rider] Requesting Trip from Zarqa...`); const tripRequest = await api('POST', '/trips', { city: 'amman', service_class: 'economy', origin: { lat: 32.0650, lng: 36.0830 }, // Zarqa origin destination: { lat: 32.0700, lng: 36.0900 } }, riderToken); console.log(`\x1b[32m[Rider] Trip created: ${tripRequest.id}\x1b[0m`); // 6. Simulate Trip Flow (Wait 10 seconds per state) await new Promise(r => setTimeout(r, 10000)); if (tripId) { console.log(`\n[Driver] Arriving at pickup...`); await api('PATCH', `/trips/${tripId}/status`, { status: 'driver_arrived' }, driverToken); await new Promise(r => setTimeout(r, 5000)); console.log(`\n[Driver] Starting Trip...`); await api('PATCH', `/trips/${tripId}/status`, { status: 'in_progress' }, driverToken); console.log(`\n[System] Simulating 1-minute ride to destination...`); // Simulate 30 seconds wait await new Promise(r => setTimeout(r, 30000)); console.log(`[System] Halfway there...`); await new Promise(r => setTimeout(r, 30000)); console.log(`\n[Driver] Completing Trip...`); await api('PATCH', `/trips/${tripId}/status`, { status: 'completed' }, driverToken); await new Promise(r => setTimeout(r, 2000)); console.log(`\n[Driver] Collecting Cash...`); await api('PATCH', `/trips/${tripId}/status`, { status: 'paid' }, driverToken); console.log('\n\x1b[32m🎉 Simulation Completed Successfully! 🎉\x1b[0m\n'); } else { console.log('\n\x1b[31mFailed to receive dispatch!\x1b[0m'); } // Cleanup clearInterval(locationInterval); driverSocket.disconnect(); riderSocket.disconnect(); rl.close(); } run().catch(err => { console.error('\x1b[31mSimulation Failed!\x1b[0m', err); process.exit(1); });