/**
 * FCM Service - Platform-aware push notification handling
 * 
 * Native (Android/iOS): Uses @react-native-firebase/messaging
 * Web: Uses Firebase JS SDK with service workers (limited support)
 */
import { Platform } from 'react-native';
import {
    doc,
    FieldValue,
    isWeb,
} from '../firebase';

// Only import native messaging on native platforms
let messaging: any = null;
if (Platform.OS !== 'web') {
    messaging = require('@react-native-firebase/messaging').default;
}

export class FCMService {
    private static tokenRefreshUnsubscribe: (() => void) | null = null;

    /**
     * Check if FCM is supported on current platform
     */
    static isSupported(): boolean {
        // FCM is fully supported on Android
        // Limited support on web (requires service worker setup)
        // iOS uses APNs through FCM
        return Platform.OS === 'android' || Platform.OS === 'ios';
    }

    /**
     * Request notification permissions
     */
    static async requestPermission(): Promise<boolean> {
        // Web handling
        if (Platform.OS === 'web') {
            if (typeof window === 'undefined' || !('Notification' in window)) {
                console.log('Notifications not supported in this browser');
                return false;
            }

            try {
                const permission = await Notification.requestPermission();
                return permission === 'granted';
            } catch (error) {
                console.error('Error requesting notification permission:', error);
                return false;
            }
        }

        // Native handling (Android/iOS)
        if (!messaging) {
            return false;
        }

        try {
            const authStatus = await messaging().requestPermission();
            const enabled =
                authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
                authStatus === messaging.AuthorizationStatus.PROVISIONAL;

            if (!enabled) {
                console.warn('User notification permission denied');
            }

            return enabled;
        } catch (error) {
            console.error('Error requesting notification permission:', error);
            return false;
        }
    }

    /**
     * Get the FCM token
     */
    static async getToken(): Promise<string | null> {
        // Web handling
        if (Platform.OS === 'web') {
            // Web FCM requires service worker setup
            // For now, return null and log a message
            console.log('Web push notifications require additional setup (service worker, VAPID key)');
            return null;
        }

        // Native handling
        if (!messaging) {
            return null;
        }

        try {
            const token = await messaging().getToken();
            console.log('FCM Token retrieved:', token);
            return token;
        } catch (error) {
            console.error('Error getting FCM token:', error);
            return null;
        }
    }

    /**
     * Save FCM token to Firestore user document during user creation
     */
    static async saveTokenToFirestoreOnCreate(uid: string, token: string): Promise<{ success: boolean; error?: string }> {
        try {
            const userDocRef = doc('users', uid);
            await userDocRef.update({
                fcmToken: token,
                fcmTokenUpdatedAt: FieldValue.serverTimestamp(),
            });

            console.log('FCM token saved to Firestore during user creation for user:', uid);
            return { success: true };
        } catch (error) {
            console.error('Error saving FCM token to Firestore during creation:', error);
            return {
                success: false,
                error: error instanceof Error ? error.message : 'Failed to save FCM token',
            };
        }
    }

    /**
     * Update FCM token in Firestore user document
     */
    static async updateTokenInFirestore(uid: string, token: string): Promise<{ success: boolean; error?: string }> {
        try {
            const userDocRef = doc('users', uid);
            const userDoc = await userDocRef.get();

            if (!userDoc.exists) {
                console.log('User document does not exist yet, skipping token update for:', uid);
                return { success: true };
            }

            await userDocRef.update({
                fcmToken: token,
                fcmTokenUpdatedAt: FieldValue.serverTimestamp(),
            });

            console.log('FCM token updated in Firestore for user:', uid);
            return { success: true };
        } catch (error: any) {
            console.error('Error updating FCM token in Firestore:', error);

            if (error?.code === 'firestore/not-found') {
                console.log('User document not found, skipping token update');
                return { success: true };
            }

            return {
                success: false,
                error: error instanceof Error ? error.message : 'Failed to update FCM token',
            };
        }
    }

    /**
     * Remove FCM token from Firestore (on logout)
     */
    static async removeTokenFromFirestore(uid: string): Promise<{ success: boolean; error?: string }> {
        try {
            const userDocRef = doc('users', uid);
            await userDocRef.update({
                fcmToken: FieldValue.delete(),
                fcmTokenUpdatedAt: FieldValue.serverTimestamp(),
            });

            console.log('FCM token removed from Firestore for user:', uid);
            return { success: true };
        } catch (error) {
            console.error('Error removing FCM token from Firestore:', error);
            return {
                success: false,
                error: error instanceof Error ? error.message : 'Failed to remove FCM token',
            };
        }
    }

    /**
     * Initialize FCM token for a new user (during user creation)
     */
    static async initializeTokenForNewUser(uid: string): Promise<{ success: boolean; error?: string; token?: string }> {
        // Skip on web
        if (Platform.OS === 'web') {
            console.log('Skipping FCM token initialization on web');
            return { success: true };
        }

        try {
            const hasPermission = await this.requestPermission();
            if (!hasPermission) {
                console.warn('Notification permission not granted, continuing anyway...');
            }

            const token = await this.getToken();
            if (!token) {
                return { success: false, error: 'Failed to retrieve FCM token' };
            }

            const saveResult = await this.saveTokenToFirestoreOnCreate(uid, token);
            if (!saveResult.success) {
                return saveResult;
            }

            this.setupTokenRefreshListener(uid);

            return { success: true, token };
        } catch (error) {
            console.error('Error initializing FCM token for new user:', error);
            return {
                success: false,
                error: error instanceof Error ? error.message : 'Failed to initialize FCM token',
            };
        }
    }

    /**
     * Update FCM token for an existing user
     */
    static async updateTokenForExistingUser(uid: string): Promise<{ success: boolean; error?: string }> {
        // Skip on web
        if (Platform.OS === 'web') {
            return { success: true };
        }

        try {
            const hasPermission = await this.requestPermission();
            if (!hasPermission) {
                console.warn('Notification permission not granted, continuing anyway...');
            }

            const token = await this.getToken();
            if (!token) {
                return { success: false, error: 'Failed to retrieve FCM token' };
            }

            const updateResult = await this.updateTokenInFirestore(uid, token);
            if (!updateResult.success) {
                return updateResult;
            }

            this.setupTokenRefreshListener(uid);

            return { success: true };
        } catch (error) {
            console.error('Error updating FCM token:', error);
            return {
                success: false,
                error: error instanceof Error ? error.message : 'Failed to update FCM token',
            };
        }
    }

    /**
     * Set up a listener for FCM token refresh (native only)
     */
    static setupTokenRefreshListener(uid: string): void {
        if (Platform.OS === 'web' || !messaging) {
            return;
        }

        if (this.tokenRefreshUnsubscribe) {
            this.tokenRefreshUnsubscribe();
            this.tokenRefreshUnsubscribe = null;
        }

        this.tokenRefreshUnsubscribe = messaging().onTokenRefresh(async (token: string) => {
            console.log('FCM token refreshed:', token);
            await this.updateTokenInFirestore(uid, token);
        });
    }

    /**
     * Clean up token refresh listener
     */
    static cleanup(): void {
        if (this.tokenRefreshUnsubscribe) {
            this.tokenRefreshUnsubscribe();
            this.tokenRefreshUnsubscribe = null;
        }
    }

    /**
     * Set up foreground message handler (native only)
     */
    static setupForegroundMessageHandler(): () => void {
        if (Platform.OS === 'web' || !messaging) {
            return () => { };
        }

        return messaging().onMessage(async (remoteMessage: any) => {
            console.log('Foreground FCM message received:', remoteMessage);

            if (remoteMessage.notification) {
                console.log('Notification:', remoteMessage.notification);
            }
        });
    }

    /**
     * Set up background message handler (native only)
     */
    static setupBackgroundMessageHandler(): void {
        if (Platform.OS === 'web' || !messaging) {
            return;
        }

        messaging().setBackgroundMessageHandler(async (remoteMessage: any) => {
            console.log('Background FCM message received:', remoteMessage);
        });
    }

    /**
     * Get the initial notification when app is opened from a notification
     */
    static async getInitialNotification(): Promise<any | null> {
        if (Platform.OS === 'web' || !messaging) {
            return null;
        }

        try {
            const remoteMessage = await messaging().getInitialNotification();
            if (remoteMessage) {
                console.log('App opened from notification:', remoteMessage);
            }
            return remoteMessage;
        } catch (error) {
            console.error('Error getting initial notification:', error);
            return null;
        }
    }

    /**
     * Set up notification opened handler
     */
    static setupNotificationOpenedHandler(callback: (remoteMessage: any) => void): () => void {
        if (Platform.OS === 'web' || !messaging) {
            return () => { };
        }

        return messaging().onNotificationOpenedApp((remoteMessage: any) => {
            console.log('Notification opened app:', remoteMessage);
            callback(remoteMessage);
        });
    }
}
