// supabase/functions/send-campaign-batch/index.ts
import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
import { Resend } from "npm:resend@2.0.0";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.49.1";

const resend = new Resend(Deno.env.get("RESEND_API_KEY"));

const corsHeaders = {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
    "Access-Control-Allow-Methods": "POST, OPTIONS",
};

interface BatchRequest {
    campaign_id: string;
    batch_size?: number;
}

function json(status: number, body: Record<string, unknown>) {
    return new Response(JSON.stringify(body), {
        status,
        headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
}

function renderTemplate(input: string, vars: Record<string, string>) {
    let out = input;
    for (const [k, v] of Object.entries(vars)) {
        out = out.replaceAll(`{{${k}}}`, v ?? "");
    }
    return out;
}

async function countByStatus(supabase: any, campaignId: string, status: string) {
    const { count, error } = await supabase
        .from("campaign_recipients")
        .select("*", { count: "exact", head: true })
        .eq("campaign_id", campaignId)
        .eq("status", status);

    if (error) throw error;
    return count || 0;
}

serve(async (req: Request): Promise<Response> => {
    if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders });

    try {
        const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
        const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
        const supabase = createClient(supabaseUrl, supabaseServiceKey, {
            auth: { persistSession: false },
        });

        // Require auth
        const authHeader = req.headers.get("Authorization");
        if (!authHeader) return json(401, { error: "Missing Authorization header" });

        const token = authHeader.replace("Bearer ", "");
        const { data: userRes, error: userErr } = await supabase.auth.getUser(token);
        if (userErr || !userRes?.user) return json(401, { error: "Invalid token" });

        const { campaign_id, batch_size = 50 }: BatchRequest = await req.json();
        if (!campaign_id) return json(400, { error: "campaign_id is required" });

        // Fetch campaign
        const { data: campaign, error: campaignError } = await supabase
            .from("campaigns")
            .select("*")
            .eq("id", campaign_id)
            .maybeSingle();

        if (campaignError || !campaign) return json(404, { error: "Campaign not found" });

        // Ownership check (prevents users from sending other users' campaigns)
        if (campaign.created_by !== userRes.user.id) {
            return json(403, { error: "Forbidden: you do not own this campaign" });
        }

        if (campaign.status !== "active") {
            return json(200, { status: "skipped", reason: `Campaign not active (status: ${campaign.status})` });
        }

        // Sender
        const { data: business } = await supabase
            .from("business")
            .select("name, email")
            .limit(1)
            .maybeSingle();

        const senderName = business?.name || Deno.env.get("DEFAULT_FROM_NAME") || "Your Business";
        const senderEmail = business?.email || Deno.env.get("DEFAULT_FROM_EMAIL") || "onboarding@resend.dev";

        // Fetch pending recipients
        const { data: recipients, error: recipientsError } = await supabase
            .from("campaign_recipients")
            .select(
                `
        id,
        contact_id,
        created_at,
        contacts!inner (
          id,
          email,
          first_name,
          last_name,
          company
        )
      `
            )
            .eq("campaign_id", campaign_id)
            .eq("status", "pending")
            .order("created_at", { ascending: true })
            .limit(batch_size);

        if (recipientsError) return json(500, { error: "Failed to fetch recipients" });

        if (!recipients || recipients.length === 0) {
            const now = new Date().toISOString();

            // Recount and complete
            const sentCount = await countByStatus(supabase, campaign_id, "sent");
            const failedCount = await countByStatus(supabase, campaign_id, "failed");
            const skippedCount = await countByStatus(supabase, campaign_id, "skipped");

            await supabase
                .from("campaigns")
                .update({
                    status: "completed",
                    completed_at: now,
                    last_batch_at: now,
                    sent_count: sentCount,
                    failed_count: failedCount,
                    skipped_count: skippedCount,
                })
                .eq("id", campaign_id);

            return json(200, {
                status: "completed",
                message: "All emails sent",
                sent: sentCount,
                failed: failedCount,
                skipped: skippedCount,
                pending_remaining: 0,
            });
        }

        // Suppression check for emails in this batch only
        const emails = recipients.map((r: any) => r.contacts.email).filter(Boolean);
        const { data: suppressedEmails } = await supabase
            .from("suppression_list")
            .select("email")
            .in("email", emails);

        const suppressedSet = new Set((suppressedEmails || []).map((s: any) => s.email));

        let sentInThisBatch = 0;
        let failedInThisBatch = 0;
        let skippedInThisBatch = 0;

        for (const recipient of recipients) {
            const contact = recipient.contacts as any;
            const recipientId = recipient.id;

            if (!contact?.email) {
                await supabase
                    .from("campaign_recipients")
                    .update({ status: "failed", error_message: "Missing contact email" })
                    .eq("id", recipientId);

                failedInThisBatch++;
                continue;
            }

            if (suppressedSet.has(contact.email)) {
                await supabase
                    .from("campaign_recipients")
                    .update({ status: "skipped", error_message: "Email suppressed" })
                    .eq("id", recipientId);

                skippedInThisBatch++;
                continue;
            }

            const vars = {
                first_name: contact.first_name || "",
                last_name: contact.last_name || "",
                email: contact.email || "",
                company: contact.company || "",
            };

            const renderedSubject = renderTemplate(campaign.subject, vars);
            const renderedHtml = renderTemplate(campaign.html_body, vars);
            const renderedText = campaign.text_body ? renderTemplate(campaign.text_body, vars) : undefined;

            const unsubscribeUrl =
                `${supabaseUrl}/functions/v1/handle-unsubscribe` +
                `?email=${encodeURIComponent(contact.email)}` +
                `&campaign_id=${encodeURIComponent(campaign_id)}`;

            const htmlWithUnsubscribe =
                renderedHtml +
                `
<div style="margin-top: 40px; padding-top: 20px; border-top: 1px solid #eee; text-align: center; font-size: 12px; color: #666;">
  <p>You received this email because you are subscribed to our mailing list.</p>
  <p><a href="${unsubscribeUrl}" style="color: #666;">Unsubscribe</a></p>
</div>
`;

            try {
                const emailResponse = await resend.emails.send({
                    from: `${senderName} <${senderEmail}>`,
                    to: [contact.email],
                    subject: renderedSubject,
                    html: htmlWithUnsubscribe,
                    text: renderedText,
                });

                if (emailResponse.error) throw new Error(emailResponse.error.message);

                await supabase
                    .from("campaign_recipients")
                    .update({ status: "sent", sent_at: new Date().toISOString(), error_message: null })
                    .eq("id", recipientId);

                await supabase.from("email_logs").insert({
                    campaign_id,
                    contact_id: contact.id,
                    recipient_email: contact.email,
                    subject: renderedSubject,
                    status: "sent",
                    resend_id: emailResponse.data?.id,
                });

                sentInThisBatch++;

                // gentle pacing
                await new Promise((resolve) => setTimeout(resolve, 100));
            } catch (err: any) {
                const message = err?.message || "Unknown send error";

                await supabase
                    .from("campaign_recipients")
                    .update({ status: "failed", error_message: message })
                    .eq("id", recipientId);

                await supabase.from("email_logs").insert({
                    campaign_id,
                    contact_id: contact.id,
                    recipient_email: contact.email,
                    subject: renderedSubject,
                    status: "failed",
                    error_message: message,
                });

                failedInThisBatch++;
            }
        }

        // Recount for accuracy
        const sentCount = await countByStatus(supabase, campaign_id, "sent");
        const failedCount = await countByStatus(supabase, campaign_id, "failed");
        const skippedCount = await countByStatus(supabase, campaign_id, "skipped");
        const pendingRemaining = await countByStatus(supabase, campaign_id, "pending");

        const now = new Date().toISOString();
        const nextStatus = pendingRemaining === 0 ? "completed" : "active";

        await supabase
            .from("campaigns")
            .update({
                status: nextStatus,
                completed_at: pendingRemaining === 0 ? now : null,
                last_batch_at: now,
                sent_count: sentCount,
                failed_count: failedCount,
                skipped_count: skippedCount,
            })
            .eq("id", campaign_id);

        return json(200, {
            status: pendingRemaining === 0 ? "completed" : "batch_complete",
            sent: sentInThisBatch,
            failed: failedInThisBatch,
            skipped: skippedInThisBatch,
            totals: {
                sent: sentCount,
                failed: failedCount,
                skipped: skippedCount,
            },
            pending_remaining: pendingRemaining,
        });
    } catch (error: any) {
        return json(500, { error: error?.message || "Batch processing error" });
    }
});