import { bus } from '../../lib/event-bus.js';
import { getProduct } from '../products/cache.js';
import { getById as getUserById } from '../auth/repository.js';
import { dispatchEmail } from './dispatcher.js';

// ── Event Bus Subscribers ────────────────────────────────────
// Connects the Event Bus to the delivery module.
// Handlers are fire-and-forget — errors are logged, never thrown.

const noopLog = {
  info: (..._a: unknown[]) => {},
  error: (..._a: unknown[]) => {},
};

/**
 * Register all delivery-related event subscribers.
 * Call this once at service startup.
 */
export function registerDeliverySubscribers(
  log: { info: (...a: unknown[]) => void; error: (...a: unknown[]) => void } = noopLog
): void {
  // Welcome email on user creation
  bus.on('user.created', async event => {
    try {
      await dispatchEmail(
        {
          to: event.payload.email,
          templateId: 'welcome',
          variables: {
            displayName: event.payload.email.split('@')[0],
            productName: resolveProductName(event.payload.productId),
            dashboardUrl: resolveDashboardUrl(event.payload.productId),
          },
          productId: event.payload.productId,
          userId: event.payload.userId,
        },
        log
      );
    } catch (err) {
      log.error({ err, eventId: event.id }, '[delivery/subscriber] Failed to send welcome email');
    }
  });

  // Password reset email
  bus.on('user.password_reset', async event => {
    try {
      const baseUrl = resolveDashboardUrl(event.payload.productId);
      const resetUrl = `${baseUrl}/reset-password?token=${event.payload.resetToken}`;
      await dispatchEmail(
        {
          to: event.payload.email,
          templateId: 'password-reset',
          variables: {
            displayName: event.payload.displayName || event.payload.email.split('@')[0],
            productName: resolveProductName(event.payload.productId),
            resetUrl,
          },
          productId: event.payload.productId,
          userId: event.payload.userId,
        },
        log
      );
    } catch (err) {
      log.error(
        { err, eventId: event.id },
        '[delivery/subscriber] Failed to send password reset email'
      );
    }
  });

  // Email verification request — send verification email
  bus.on('user.email_verification_requested', async event => {
    try {
      const baseUrl = resolveDashboardUrl(event.payload.productId);
      const verifyUrl = `${baseUrl}/verify-email?token=${event.payload.verificationToken}`;
      await dispatchEmail(
        {
          to: event.payload.email,
          templateId: 'email-verification',
          variables: {
            displayName: event.payload.displayName || event.payload.email.split('@')[0],
            productName: resolveProductName(event.payload.productId),
            verifyUrl,
          },
          productId: event.payload.productId,
          userId: event.payload.userId,
        },
        log
      );
    } catch (err) {
      log.error(
        { err, eventId: event.id },
        '[delivery/subscriber] Failed to send email verification'
      );
    }
  });

  // Email verified — confirmation (no email needed)
  bus.on('user.email_verified', async event => {
    log.info(
      { userId: event.payload.userId, productId: event.payload.productId },
      '[delivery/subscriber] Email verified — no email to send'
    );
  });

  // Payment failed notification
  bus.on('payment.failed', async event => {
    try {
      const user = await resolveUserEmail(event.payload.userId);
      if (!user) {
        log.error(
          { userId: event.payload.userId },
          '[delivery/subscriber] payment.failed — user not found, skipping email'
        );
        return;
      }
      const productId = event.payload.productId || 'bytelyst';
      const baseUrl = resolveDashboardUrl(productId);
      await dispatchEmail(
        {
          to: user.email,
          templateId: 'payment-failed',
          variables: {
            displayName: user.displayName,
            productName: resolveProductName(productId),
            amount: String(event.payload.amount ?? ''),
            currency: event.payload.currency ?? 'usd',
            billingUrl: `${baseUrl}/billing`,
          },
          productId,
          userId: event.payload.userId,
        },
        log
      );
    } catch (err) {
      log.error(
        { err, eventId: event.id },
        '[delivery/subscriber] Failed to handle payment.failed'
      );
    }
  });

  // Subscription trial expiring
  bus.on('subscription.trial_expiring', async event => {
    try {
      const user = await resolveUserEmail(event.payload.userId);
      if (!user) {
        log.error(
          { userId: event.payload.userId },
          '[delivery/subscriber] trial_expiring — user not found, skipping email'
        );
        return;
      }
      const productId = event.payload.productId || 'bytelyst';
      const baseUrl = resolveDashboardUrl(productId);
      const daysLeft = event.payload.expiresAt
        ? String(
            Math.max(
              0,
              Math.ceil((new Date(event.payload.expiresAt).getTime() - Date.now()) / 86_400_000)
            )
          )
        : '3';
      await dispatchEmail(
        {
          to: user.email,
          templateId: 'trial-expiring',
          variables: {
            displayName: user.displayName,
            productName: resolveProductName(productId),
            daysLeft,
            upgradeUrl: `${baseUrl}/billing`,
          },
          productId,
          userId: event.payload.userId,
        },
        log
      );
    } catch (err) {
      log.error(
        { err, eventId: event.id },
        '[delivery/subscriber] Failed to handle subscription.trial_expiring'
      );
    }
  });

  // Subscription trial expired
  bus.on('subscription.trial_expired', async event => {
    try {
      const user = await resolveUserEmail(event.payload.userId);
      if (!user) {
        log.error(
          { userId: event.payload.userId },
          '[delivery/subscriber] trial_expired — user not found, skipping email'
        );
        return;
      }
      const productId = event.payload.productId || 'bytelyst';
      const baseUrl = resolveDashboardUrl(productId);
      await dispatchEmail(
        {
          to: user.email,
          templateId: 'trial-expired',
          variables: {
            displayName: user.displayName,
            productName: resolveProductName(productId),
            upgradeUrl: `${baseUrl}/billing`,
          },
          productId,
          userId: event.payload.userId,
        },
        log
      );
    } catch (err) {
      log.error(
        { err, eventId: event.id },
        '[delivery/subscriber] Failed to handle subscription.trial_expired'
      );
    }
  });

  log.info('[delivery] Registered event bus subscribers');
}

// ── Helpers ──────────────────────────────────────────────────

async function resolveUserEmail(
  userId: string
): Promise<{ email: string; displayName: string } | null> {
  try {
    const user = await getUserById(userId);
    if (!user?.email) return null;
    return {
      email: user.email,
      displayName: user.displayName || user.email.split('@')[0],
    };
  } catch {
    return null;
  }
}

function resolveDashboardUrl(productId: string): string {
  const envKey = `${productId.toUpperCase()}_DASHBOARD_URL`;
  const envUrl = process.env[envKey];
  if (envUrl) return envUrl;
  const product = getProduct(productId);
  if (product?.websiteUrl) return product.websiteUrl;
  return `https://${productId}.bytelyst.com`;
}

function resolveProductName(productId: string): string {
  const product = getProduct(productId);
  return product?.displayName || productId;
}
