
const webPush = require('web-push')

import common from '../../src/helpers/common';

//generate and store VAPID keys in .env.local if not already done
if (!process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY || !process.env.WEB_PUSH_PRIVATE_KEY) {
    const { publicKey, privateKey } = webPush.generateVAPIDKeys()
    console.log('VAPID keys generated:')
    console.log('Public key:', publicKey)
    console.log('Private key:', privateKey)
    console.log('Store these keys in your .env.local file:')
    console.log('NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY=', publicKey)
    console.log('WEB_PUSH_PRIVATE_KEY=', privateKey)
    process.exit(0)
}

webPush.setVapidDetails(
    `mailto:${process.env.WEB_PUSH_EMAIL}`,
    process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY,
    process.env.WEB_PUSH_PRIVATE_KEY
)

const Notification = async (req, res) => {
    if (req.method == 'GET') {
        res.statusCode = 200
        res.setHeader('Allow', 'POST')
        let subs = 0
        if (req.query && req.query.id) {
            const prisma = common.getPrismaClient();
            const publisher = await prisma.publisher.findUnique({
                where: { id: req.query.id },
                select: { pushSubscription: true }
            });
            subs = Array.isArray(publisher.pushSubscription) ? publisher.pushSubscription.length : (publisher.pushSubscription ? 1 : 0);
            res.send({ subs })
            res.end()
            return
        } else {
            // send the public key in the response headers
            //res.setHeader('Content-Type', 'text/plain')
            res.send({ pk: process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY, subs })
            res.end()
        }
    }
    if (req.method == 'PUT') {
        // store the subscription object in the database
        // publisher.pushSubscription = subscription
        const prisma = common.getPrismaClient();
        const { subscription, id, name } = req.body
        const publisher = await prisma.publisher.findUnique({
            where: { id },
            select: { pushSubscription: true }
        });

        if (!publisher) {
            res.statusCode = 404
            res.end()
            return
        }

        let subscriptions = Array.isArray(publisher.pushSubscription) ? publisher.pushSubscription : (publisher.pushSubscription ? [publisher.pushSubscription] : []);
        const index = subscriptions.findIndex(sub => sub.endpoint === subscription.endpoint);

        if (index !== -1) {
            subscriptions[index] = subscription; // Update existing subscription
            console.log('Subscription for publisher', id, 'updated.')
        } else {
            subscriptions.push(subscription); // Add new subscription
            console.log('Subscription for publisher', id, 'saved.')
        }

        await prisma.publisher.update({
            where: { id },
            data: { pushSubscription: subscriptions }
        });
        console.log('Subscription update successful', subscription.keys.auth, ". Total subscriptions:", subscriptions.length)
        res.send({ subs: subscriptions.length })
        res.statusCode = 200
        res.end()
    }
    if (req.method == 'DELETE') {
        // remove the subscription object from the database
        // publisher.pushSubscription = null
        const prisma = common.getPrismaClient();
        const { subscriptionId, id } = req.body;

        const publisher = await prisma.publisher.findUnique({
            where: { id },
            select: { pushSubscription: true }
        });

        let subscriptions = Array.isArray(publisher.pushSubscription) ? publisher.pushSubscription : (publisher.pushSubscription ? [publisher.pushSubscription] : []);
        try {
            subscriptions = subscriptionId ? subscriptions.filter(sub => sub.endpoint !== subscriptionId) : [];
            await prisma.publisher.update({
                where: { id },
                data: { pushSubscription: subscriptions }
            });
        } catch (e) {
            console.log(e)
            await prisma.publisher.update({
                where: { id },
                data: { pushSubscription: null }
            });
        }

        console.log('Subscription for publisher', id, 'deleted')
        res.send({ subs: subscriptions.length })
        res.statusCode = 200
        res.end()
    }


    if (req.method == 'POST') {//title = "ССС", message = "Ще получите уведомление по този начин.")
        const { subscription, id, ids, broadcast, title = 'ССОМ', message = 'Ще получавате уведомления така.', actions } = req.body
        if (broadcast) {
            await broadcastPush(title, message, actions)
            res.statusCode = 200
            res.end()
            return
        } else if (ids && ids.length) {
            console.log('Sending push notifications to publishers ', ids);
            await Promise.all(ids.map(_id => sendPush(_id, title, message, actions)));
            res.statusCode = 200;
            res.end();
            return;
        } else if (id) {
            console.log('Sending push notification to publisher ', id)
            await sendPush(id, title, message, actions)
            res.statusCode = 200
            res.end()
            return
        } else if (subscription) {
            await webPush
                .sendNotification(
                    subscription,
                    JSON.stringify({ title, message, actions })
                )
                .then(response => {
                    res.writeHead(response.statusCode, response.headers).end(response.body)
                })
                .catch(err => {
                    if ('statusCode' in err) {
                        res.writeHead(err.statusCode, err.headers).end(err.body)
                    } else {
                        console.error(err)
                        res.statusCode = 500
                        res.end()
                    }
                })
        }
    } else {
        res.statusCode = 405
        res.end()
    }
}

export default Notification

//export pushNotification(userId or email) for use in other files
export const sendPush = async (id, title, message, actions) => {
    const prisma = common.getPrismaClient();
    const publisher = await prisma.publisher.findUnique({
        where: { id }
    })

    if (publisher.pushSubscription && Array.isArray(publisher.pushSubscription) && publisher.pushSubscription.length) {
        for (const subscription of publisher.pushSubscription) {
            await webPush
                .sendNotification(
                    subscription,
                    JSON.stringify({ title, message, actions })
                )
                .then(response => {
                    console.log('Push notification sent to publisher', id)
                })
                .catch(err => {
                    console.error('Error sending push notification to publisher', id, ':', err)
                })
        }
    } else {
        console.log('No valid subscriptions found for publisher', id)

    }
}
//export breoadcastNotification for use in other files
export const broadcastPush = async (title, message, actions) => {
    const prisma = common.getPrismaClient();
    const publishers = await prisma.publisher.findMany({
        where: { pushSubscription: { not: null } }
    })

    for (const publisher of publishers) {
        if (Array.isArray(publisher.pushSubscription) && publisher.pushSubscription.length) {
            for (const subscription of publisher.pushSubscription) {
                await webPush.sendNotification(
                    subscription, // Here subscription is each individual subscription object
                    JSON.stringify({ title, message, actions })
                )
                    .then(response => {
                        console.log('Push notification sent to device', subscription.endpoint, 'of publisher', publisher.id);
                    })
                    .catch(err => {
                        console.error('Error sending push notification to device', subscription.endpoint, 'of publisher', publisher.id, ':', err);
                        // Optionally handle failed subscriptions, e.g., remove outdated or invalid subscriptions
                    });
            }
        } else {
            console.log('No valid subscriptions found for publisher', publisher.id);
        }
    }
}
