import { query, queryOne } from '../db';
import { logger } from '../logger';
import { createOutboundTransporter } from '../mailer';
import { finalizeCampaignStatus, listUnsubscribeMailHeaders } from './campaignSender';
import { rewriteLinks } from './linkRewriter';
import { withSmtpRetry } from './smtpRetry';

const BASE_URL = process.env.APP_BASE_URL || 'http://localhost:3002';

interface SettingsRow {
  send_from_email: string | null;
  send_from_name: string | null;
  reply_unsubscribe_enabled: boolean;
  auto_bcc_emails: string[];
}

interface EnrichedRow {
  id: string;
  contact_id: string;
  enriched_subject: string;
  enriched_body: string;
}

interface RecipientRow {
  id: string;
  track_token: string;
}

interface CampaignRow {
  id: string;
  reply_to: string | null;
  from_name: string;
  from_email: string;
}

/**
 * Send all approved enriched rows for a campaign; updates statuses and campaign to sent.
 */
export async function sendApprovedEnrichedEmails(campaignId: string): Promise<void> {
  const settings = await queryOne<SettingsRow>(
    `SELECT send_from_email, send_from_name, reply_unsubscribe_enabled, auto_bcc_emails
     FROM campaign_settings WHERE campaign_id = $1`,
    [campaignId]
  );

  const campaign = await queryOne<CampaignRow>(
    `SELECT id, reply_to, from_name, from_email FROM campaigns WHERE id = $1`,
    [campaignId]
  );
  if (!campaign) throw new Error('Campaign not found');

  const fromName = settings?.send_from_name || campaign.from_name;
  const fromEmail = settings?.send_from_email || campaign.from_email;
  const bccList = (settings?.auto_bcc_emails || []).filter(Boolean);
  const skipListUnsub = settings?.reply_unsubscribe_enabled === true;

  const rows = await query<EnrichedRow>(
    `SELECT id, contact_id, enriched_subject, enriched_body
     FROM campaign_enriched_emails
     WHERE campaign_id = $1 AND status = 'approved'
       AND enriched_subject IS NOT NULL AND enriched_body IS NOT NULL`,
    [campaignId]
  );

  if (rows.length === 0) return;

  const contacts = await query<{ id: string; email: string }>(
    `SELECT id, email FROM contacts WHERE id = ANY($1::uuid[])`,
    [rows.map(r => r.contact_id)]
  );
  const emailByContact = new Map(contacts.map(c => [c.id, c.email]));

  await query(`UPDATE campaigns SET status = 'sending', updated_at = now() WHERE id = $1`, [campaignId]);

  const transporter = await createOutboundTransporter();

  try {
  for (const row of rows) {
    const to = emailByContact.get(row.contact_id);
    if (!to) continue;

    await query(
      `INSERT INTO campaign_recipients (campaign_id, contact_id)
       VALUES ($1, $2)
       ON CONFLICT (campaign_id, contact_id) DO NOTHING`,
      [campaignId, row.contact_id]
    );

    const recipient = await queryOne<RecipientRow>(
      `SELECT id, track_token FROM campaign_recipients
       WHERE campaign_id = $1 AND contact_id = $2`,
      [campaignId, row.contact_id]
    );
    if (!recipient) continue;

    try {
      let html = row.enriched_body;
      html = await rewriteLinks(html, campaignId, recipient.track_token);

      const pixel = `<img src="${BASE_URL}/track/open/${recipient.track_token}.gif" width="1" height="1" alt="" style="display:none;border:0;" />`;
      if (/<\/body>/i.test(html)) {
        html = html.replace(/<\/body>/i, `${pixel}</body>`);
      } else {
        html = `${html}${pixel}`;
      }

      const mail: Parameters<typeof transporter.sendMail>[0] = {
        from: `"${fromName}" <${fromEmail}>`,
        replyTo: campaign.reply_to || undefined,
        to,
        subject: row.enriched_subject,
        html,
        bcc: bccList.length ? bccList : undefined,
        headers: {
          'X-Email-Campaigner-Campaign-Id': campaignId,
          'X-Email-Campaigner-Contact-Id': row.contact_id,
          ...(skipListUnsub
            ? {}
            : listUnsubscribeMailHeaders(`${BASE_URL}/track/unsubscribe/${recipient.track_token}`)),
        },
      };

      const info = await withSmtpRetry(() => transporter.sendMail(mail));
      const messageId =
        typeof info.messageId === 'string' ? info.messageId.replace(/[<>]/g, '') : undefined;

      await query(
        `UPDATE campaign_recipients SET status = 'sent', sent_at = now() WHERE id = $1`,
        [recipient.id]
      );
      await query(`INSERT INTO email_events (campaign_id, contact_id, type) VALUES ($1, $2, 'sent')`, [
        campaignId,
        row.contact_id,
      ]);
      await query(
        `UPDATE campaign_enriched_emails SET status = 'sent', sent_at = now(), outbound_message_id = $1, updated_at = now()
         WHERE id = $2`,
        [messageId || null, row.id]
      );
    } catch (err) {
      logger.error({ err, to, campaignId }, '[enriched-send] failed');
      await query(
        `UPDATE campaign_recipients SET status = 'failed' WHERE id = $1`,
        [recipient.id]
      );
      await query(
        `UPDATE campaign_enriched_emails SET status = 'failed', error_message = $1, updated_at = now() WHERE id = $2`,
        [err instanceof Error ? err.message : String(err), row.id]
      );
    }
  }
  } finally {
    await finalizeCampaignStatus(campaignId);
  }
}
