import { NextResponse } from 'next/server';
import { withErrorHandler, RouteContext } from '@server/middleware/withErrorHandler';
import { withAuth, requireSection, AuthedRequest } from '@server/middleware/withAuth';
import { requirePlanFeature } from '@server/utils/features';
import { getCampaign, listCampaignDeliveries, exportAllCampaignDeliveries } from '@server/services/marketing/campaigns.service';
import { effectiveBranchId, loadAccessibleOrThrow } from '@server/utils/branch-access';
import { NotFoundError } from '@server/errors';

function escapeCsvCell(value: string | null | undefined): string {
  const s = value == null ? '' : String(value);
  // Defense-in-depth: prefix cells that start with formula-injection characters
  // (=, +, -, @) so spreadsheet apps don't interpret them as formulas.
  const safe = /^[=+\-@]/.test(s) ? `'${s}` : s;
  if (safe.includes(',') || safe.includes('"') || safe.includes('\n') || safe.includes('\r')) {
    return `"${safe.replace(/"/g, '""')}"`;
  }
  return safe;
}

export const GET = withErrorHandler(
  withAuth(async (req: AuthedRequest, ctx: RouteContext) => {
    const restaurantId = req.session.restaurantId!;
    await requireSection(req, 'marketing');
    await requirePlanFeature(restaurantId, 'marketing');
    const { id } = await ctx.params;

    await loadAccessibleOrThrow(
      await getCampaign(restaurantId, id, effectiveBranchId(req.session)),
      () => getCampaign(restaurantId, id, null),
      'Campaign',
    );

    const url = new URL(req.url);
    const format = url.searchParams.get('format');
    const page = Math.max(1, parseInt(url.searchParams.get('page') ?? '1', 10) || 1);
    const pageSize = Math.min(200, Math.max(1, parseInt(url.searchParams.get('pageSize') ?? '50', 10) || 50));

    if (format === 'csv') {
      const items = await exportAllCampaignDeliveries(restaurantId, id);
      if (!items) throw new NotFoundError('Campaign');

      const header = ['recipient', 'status', 'error', 'attempts', 'updated_at'].join(',');
      const lines = items.map((r) =>
        [
          escapeCsvCell(r.recipient),
          escapeCsvCell(r.status),
          escapeCsvCell(r.last_error),
          String(r.attempts),
          escapeCsvCell(r.updated_at),
        ].join(',')
      );
      const csv = [header, ...lines].join('\r\n');
      return new Response(csv, {
        status: 200,
        headers: {
          'Content-Type': 'text/csv; charset=utf-8',
          'Content-Disposition': `attachment; filename="campaign-${id}-failures.csv"`,
          'X-Total-Rows': String(items.length),
        },
      });
    }

    const result = await listCampaignDeliveries(restaurantId, id, { page, pageSize });
    if (!result) throw new NotFoundError('Campaign');

    return NextResponse.json(result);
  })
);
