const https = require('https');
// Lazy load google-auth-library to avoid startup crashes if there are dependency issues
let GoogleAuth;
const DeviceToken = require('../models/DeviceToken');

const FCM_PROJECT_ID = process.env.FCM_PROJECT_ID;
const FCM_CLIENT_EMAIL = process.env.FCM_CLIENT_EMAIL;
const FCM_PRIVATE_KEY = process.env.FCM_PRIVATE_KEY ? process.env.FCM_PRIVATE_KEY.replace(/\\n/g, '\n') : undefined;

let authClient;

function getGoogleAuth() {
    if (!GoogleAuth) {
        try {
            GoogleAuth = require('google-auth-library').GoogleAuth;
        } catch (error) {
            throw new Error(`Failed to load google-auth-library: ${error.message}. Please run: npm install google-auth-library`);
        }
    }
    return GoogleAuth;
}

function getAuthClient() {
    if (authClient) return authClient;
    const GoogleAuthClass = getGoogleAuth();
    authClient = new GoogleAuthClass({
        credentials: {
            client_email: FCM_CLIENT_EMAIL,
            private_key: FCM_PRIVATE_KEY
        },
        scopes: ['https://www.googleapis.com/auth/firebase.messaging']
    });
    return authClient;
}

async function getAccessToken() {
    try {
        const client = await getAuthClient().getClient();
        const accessTokenResponse = await client.getAccessToken();
        if (!accessTokenResponse?.token) {
            console.error('Failed to get access token: No token in response');
            return null;
        }
        return accessTokenResponse.token;
    } catch (error) {
        console.error('Failed to get access token:', error.message);
        throw error;
    }
}

function sendFcmV1(token, payload, platform = 'android') {
    if (!token) {
        return Promise.reject(new Error('Missing device token for push message'));
    }
    if (!FCM_PROJECT_ID) {
        return Promise.reject(new Error('FCM_PROJECT_ID is not configured'));
    }
    
    const path = `/v1/projects/${FCM_PROJECT_ID}/messages:send`;
    
    // Build data object - include notification title/body in data for Flutter to handle display
    const data = {
        ...(payload.data || {}),
        // Include notification title and body in data so Flutter can display it
        ...(payload.notification?.title ? { title: payload.notification.title } : {}),
        ...(payload.notification?.body ? { body: payload.notification.body } : {})
    };
    
    // Build message - use data-only to prevent FCM auto-display duplicates
    // Flutter will handle ALL notification display via flutter_local_notifications
    // This prevents duplicate notifications (one from FCM, one from Flutter)
    const message = {
        token,
        data: data
        // Don't include notification field - Flutter handles all display
        // This prevents FCM from auto-displaying and creating duplicates
    };
    
    // Add Android-specific configuration for better delivery
    if (platform === 'android' || !platform) {
        message.android = {
            priority: 'high'
            // Don't include android.notification - this causes FCM to auto-display
            // Flutter handles all notification display
        };
    }
    
    // Ensure all data values are strings (FCM requirement)
    if (message.data) {
        Object.keys(message.data).forEach(key => {
            if (typeof message.data[key] !== 'string') {
                message.data[key] = String(message.data[key]);
            }
        });
    }
    
    const body = JSON.stringify({ message });

    return getAccessToken().then((accessToken) => {
        if (!accessToken) {
            throw new Error('Missing access token for FCM v1 - check service account credentials');
        }

        return new Promise((resolve, reject) => {
            const req = https.request(
                {
                    hostname: 'fcm.googleapis.com',
                    path,
                    method: 'POST',
                    headers: {
                        Authorization: `Bearer ${accessToken}`,
                        'Content-Type': 'application/json',
                        'Content-Length': Buffer.byteLength(body)
                    }
                },
                (res) => {
                    let responseBody = '';
                    res.on('data', (chunk) => {
                        responseBody += chunk;
                    });
                    res.on('end', () => {
                        if (res.statusCode >= 200 && res.statusCode < 300) {
                            return resolve();
                        }
                        // Try to parse error response for better error messages
                        let errorMessage = `HTTP ${res.statusCode}`;
                        try {
                            const errorData = JSON.parse(responseBody);
                            if (errorData.error?.message) {
                                errorMessage = errorData.error.message;
                            } else if (errorData.error) {
                                errorMessage = JSON.stringify(errorData.error);
                            } else {
                                errorMessage = responseBody || errorMessage;
                            }
                        } catch (e) {
                            errorMessage = responseBody || errorMessage;
                        }
                        reject(new Error(`FCM v1 push failed (${res.statusCode}): ${errorMessage}`));
                    });
                }
            );

            req.on('error', (error) => {
                console.error('FCM request error:', error.message);
                reject(error);
            });
            
            req.write(body);
            req.end();
        });
    });
}

async function sendPushToUser(userId, { notification, data } = {}) {
    const summary = {
        user_id: userId,
        attempted: 0,
        sent: 0,
        failed: 0,
        skipped: false,
        reason: null,
        details: []
    };

    if (!FCM_PROJECT_ID || !FCM_CLIENT_EMAIL || !FCM_PRIVATE_KEY) {
        console.warn('FCM v1 credentials not set; skipping push notification');
        summary.skipped = true;
        summary.reason = 'missing-credentials';
        return summary;
    }

    return new Promise((resolve) => {
        DeviceToken.findActiveByUserId(userId, (err, results) => {
            if (err) {
                console.error('Failed to fetch device tokens:', err.message);
                summary.skipped = true;
                summary.reason = 'token-query-failed';
                summary.error = err.message;
                return resolve(summary);
            }

            const rows = (results || []).filter((row) => row.push_enabled !== false);
            summary.attempted = rows.length;

            if (!rows.length) {
                summary.skipped = true;
                summary.reason = 'no-enabled-tokens';
                return resolve(summary);
            }

            Promise.all(
                rows.map((row) => {
                    const perTokenData = {
                        ...data,
                        mute_sound: row.sound_enabled === false ? '1' : '0',
                        mute_vibration: row.vibration_enabled === false ? '1' : '0'
                    };
                    return sendFcmV1(row.token, { notification, data: perTokenData }, row.platform)
                        .then(() => {
                            summary.sent += 1;
                            summary.details.push({
                                platform: row.platform,
                                status: 'sent',
                                sound_enabled: row.sound_enabled !== false,
                                vibration_enabled: row.vibration_enabled !== false
                            });
                        })
                        .catch((error) => {
                            summary.failed += 1;
                            summary.details.push({
                                platform: row.platform,
                                status: 'failed',
                                error: error.message
                            });
                            console.error(`FCM v1 push error (user ${userId}, platform ${row.platform}):`, error.message);
                        });
                })
            )
                .then(() => resolve(summary))
                .catch((error) => {
                    summary.reason = summary.reason || 'send-error';
                    summary.error = error.message;
                    resolve(summary);
                });
        });
    });
}

module.exports = { sendPushToUser };
