import { registerFcmToken, deleteFcmToken, storageGet, storageSet, storageRemove, } from '../lib/shared'; import { Capacitor, registerPlugin } from '@capacitor/core'; export const FCM_CHANNEL_ID = 'goldenchart_trade_signals'; export const FCM_USER_OPT_IN_KEY = 'gc_fcm_user_opt_in'; export const FCM_REGISTERED_KEY = 'gc_fcm_registered'; export interface FcmPayload { type?: string; market?: string; signalId?: string; signalType?: string; price?: string; } type FcmHandlers = { onForeground?: (title: string, body: string, data?: FcmPayload) => void; onTap?: (data: FcmPayload) => void; }; interface GoldenFcmPlugin { checkPermissions(): Promise<{ receive: string }>; requestPermissions(): Promise<{ receive: string }>; register(): Promise<{ value: string }>; unregister(): Promise; addListener( event: 'registration', listener: (data: { value: string }) => void, ): Promise<{ remove: () => void }>; addListener( event: 'registrationError', listener: (data: { error?: string }) => void, ): Promise<{ remove: () => void }>; addListener( event: 'pushNotificationReceived', listener: (data: { title?: string; body?: string; data?: FcmPayload }) => void, ): Promise<{ remove: () => void }>; addListener( event: 'pushNotificationActionPerformed', listener: (data: { notification?: { data?: FcmPayload } }) => void, ): Promise<{ remove: () => void }>; } const GoldenFcm = registerPlugin('GoldenFcm'); let tokenRegistered = false; let listenersAttached = false; async function userOptedIn(): Promise { return (await storageGet(FCM_USER_OPT_IN_KEY)) === '1'; } export async function markFcmUserOptIn(): Promise { await storageSet(FCM_USER_OPT_IN_KEY, '1'); } async function attachListeners(handlers: { onForeground?: (title: string, body: string, data?: FcmPayload) => void; onTap?: (data: FcmPayload) => void; }): Promise { if (listenersAttached || Capacitor.getPlatform() !== 'android') return; listenersAttached = true; await GoldenFcm.addListener('registration', async data => { try { await registerFcmToken(data.value); await storageSet(FCM_REGISTERED_KEY, '1'); } catch (e) { console.warn('[FCM] token register failed', e); } }); await GoldenFcm.addListener('registrationError', err => { console.warn('[FCM] registration error', err); void storageRemove(FCM_REGISTERED_KEY); }); await GoldenFcm.addListener('pushNotificationReceived', notification => { const title = notification.title ?? 'GoldenChart'; const body = notification.body ?? ''; handlers.onForeground?.(title, body, notification.data as FcmPayload); }); await GoldenFcm.addListener('pushNotificationActionPerformed', action => { handlers.onTap?.(action.notification?.data as FcmPayload); }); } /** ① 알림 권한만 (FCM 미호출 — 허용 직후 크래시 방지) */ export async function requestNotificationPermissionOnly(): Promise { if (Capacitor.getPlatform() !== 'android') return false; await markFcmUserOptIn(); const perm = await GoldenFcm.checkPermissions(); if (perm.receive === 'granted') return true; const req = await GoldenFcm.requestPermissions(); return req.receive === 'granted'; } /** ② 권한 허용 후 FCM 토큰 등록 */ export async function registerFcmTokenOnly(): Promise { if (Capacitor.getPlatform() !== 'android') return false; if (!(await userOptedIn())) return false; const perm = await GoldenFcm.checkPermissions(); if (perm.receive !== 'granted') return false; try { await attachListeners({}); if (tokenRegistered) return true; await new Promise(r => setTimeout(r, 800)); const result = await GoldenFcm.register(); tokenRegistered = true; if (result?.value) { await registerFcmToken(result.value); await storageSet(FCM_REGISTERED_KEY, '1'); } return !!result?.value; } catch (e) { console.warn('[FCM] register failed', e); return false; } } export async function isFcmRegisteredOnDevice(): Promise { return (await storageGet(FCM_REGISTERED_KEY)) === '1'; } /** @deprecated — requestNotificationPermissionOnly + registerFcmTokenOnly 사용 */ export async function initFcmPush(): Promise { const ok = await requestNotificationPermissionOnly(); if (!ok) return false; await new Promise(r => setTimeout(r, 1000)); return registerFcmTokenOnly(); } export async function unregisterFcmPush(): Promise { if (!Capacitor.isNativePlatform()) return; try { await deleteFcmToken(); if (Capacitor.getPlatform() === 'android' && (await userOptedIn())) { await GoldenFcm.unregister(); } } catch { /* ignore */ } tokenRegistered = false; listenersAttached = false; await storageRemove(FCM_REGISTERED_KEY); await storageRemove(FCM_USER_OPT_IN_KEY); } export async function checkPushPermission(): Promise<'granted' | 'denied' | 'prompt' | 'unknown'> { if (!Capacitor.isNativePlatform()) return 'unknown'; try { if (Capacitor.getPlatform() !== 'android') return 'unknown'; const perm = await GoldenFcm.checkPermissions(); if (perm.receive === 'granted') return 'granted'; if (perm.receive === 'denied') return 'denied'; return 'prompt'; } catch { return 'unknown'; } }