import { Router, Request, Response, NextFunction } from 'express';
import { timingSafeEqual } from 'crypto';
import { prisma } from '../../config/database';
import { env } from '../../config/env';
import { logger } from '../../utils/logger';
import { eventBus } from '../../services/event-bus.service';

const router = Router();

/**
 * POST /api/listmonk/webhook
 *
 * Handles Listmonk webhook events for reverse sync (e.g., unsubscribes).
 * Validates a shared secret via x-webhook-secret header. No JWT auth — Listmonk calls this.
 */
router.post(
  '/webhook',
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      // Accept secret from header only (query param removed — secrets must not appear in logs)
      const secret = req.headers['x-webhook-secret'] as string;
      if (!env.LISTMONK_WEBHOOK_SECRET || !secret) {
        res.status(403).json({ error: 'Invalid webhook secret' });
        return;
      }
      // Constant-time comparison to prevent timing attacks
      const incoming = Buffer.from(secret);
      const expected = Buffer.from(env.LISTMONK_WEBHOOK_SECRET);
      if (incoming.length !== expected.length || !timingSafeEqual(incoming, expected)) {
        res.status(403).json({ error: 'Invalid webhook secret' });
        return;
      }

      const event = req.body;
      const eventType = event?.event;

      if (eventType === 'subscriber.unsubscribed' || eventType === 'subscriber.disabled') {
        const email = event?.data?.subscriber?.email;
        if (!email) {
          res.json({ ok: true, action: 'skipped', reason: 'no email' });
          return;
        }

        // Publish unsubscribe event to EventBus
        eventBus.publish('listmonk.unsubscribed', {
          subscriberEmail: email,
          listId: event?.data?.list?.id ?? 0,
          listName: event?.data?.list?.name ?? '',
        });

        // Store opt-out flag in user's permissions JSON field
        const user = await prisma.user.findUnique({
          where: { email },
          select: { id: true, permissions: true },
        });

        if (user) {
          const permissions = (user.permissions as Record<string, unknown>) || {};
          permissions.listmonkOptOut = true;
          permissions.listmonkOptOutAt = new Date().toISOString();

          await prisma.user.update({
            where: { id: user.id },
            data: { permissions: permissions as any },
          });

          logger.info(`Listmonk webhook: marked user ${email} as opted-out`);
          res.json({ ok: true, action: 'opted_out', email });
          return;
        }

        logger.debug(`Listmonk webhook: no user found for ${email}`);
        res.json({ ok: true, action: 'skipped', reason: 'user not found' });
        return;
      }

      // Email open event
      if (eventType === 'campaign.view') {
        const email = event?.data?.subscriber?.email;
        const campaignId = event?.data?.campaign?.id;
        const campaignName = event?.data?.campaign?.name;
        if (email && campaignId) {
          eventBus.publish('listmonk.email.opened', {
            subscriberEmail: email,
            campaignId,
            campaignName: campaignName ?? '',
          });
        }
        res.json({ ok: true, action: 'published', eventType });
        return;
      }

      // Link click event
      if (eventType === 'campaign.link_click') {
        const email = event?.data?.subscriber?.email;
        const campaignId = event?.data?.campaign?.id;
        const campaignName = event?.data?.campaign?.name;
        const url = event?.data?.url;
        if (email && campaignId) {
          eventBus.publish('listmonk.email.clicked', {
            subscriberEmail: email,
            campaignId,
            campaignName: campaignName ?? '',
            url: url ?? '',
          });
        }
        res.json({ ok: true, action: 'published', eventType });
        return;
      }

      // Bounce event
      if (eventType === 'subscriber.bounced') {
        const email = event?.data?.subscriber?.email;
        const campaignId = event?.data?.campaign?.id;
        const bounceType = event?.data?.bounce_type ?? 'unknown';
        if (email) {
          eventBus.publish('listmonk.email.bounced', {
            subscriberEmail: email,
            campaignId: campaignId ?? 0,
            bounceType,
          });
        }
        res.json({ ok: true, action: 'published', eventType });
        return;
      }

      // Unknown event type — acknowledge but don't process
      logger.debug(`Listmonk webhook: unhandled event type "${eventType}"`);
      res.json({ ok: true, action: 'ignored', eventType });
    } catch (err) {
      next(err);
    }
  },
);

export { router as listmonkWebhookRouter };
