// hooks/useCampaigns.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { supabase } from '@/integrations/supabase/client';
import { useAuth } from '@/contexts/AuthContext';
import { toast } from 'sonner';

export interface Campaign {
    id: string;
    name: string;
    subject: string;
    html_body: string;
    text_body: string | null;
    status: 'draft' | 'active' | 'paused' | 'completed' | 'cancelled';
    segment_tags: string[] | null;
    segment_status: string[] | null;
    total_recipients: number;
    sent_count: number;
    failed_count: number;
    skipped_count: number;
    batch_size: number;
    last_batch_at: string | null;
    scheduled_at: string | null;
    completed_at: string | null;
    created_by: string;
    created_at: string;
    updated_at: string;
}

export interface CampaignInsert {
    name: string;
    subject: string;
    html_body: string;
    text_body?: string;
    segment_tags?: string[];
    segment_status?: string[];
    batch_size?: number;
    scheduled_at?: string;
}

export interface CampaignRecipient {
    id: string;
    campaign_id: string;
    contact_id: string;
    status: 'pending' | 'sent' | 'failed' | 'skipped';
    sent_at: string | null;
    error_message: string | null;
    created_at: string;
}

export interface EmailLog {
    id: string;
    campaign_id: string | null;
    contact_id: string | null;
    recipient_email: string;
    subject: string;
    status: 'sent' | 'failed' | 'bounced' | 'complained';
    resend_id: string | null;
    error_message: string | null;
    sent_at: string;
    created_at: string;
}

export interface SuppressionEntry {
    id: string;
    email: string;
    reason: 'unsubscribe' | 'bounce' | 'complaint' | 'manual';
    source_campaign_id: string | null;
    created_at: string;
}

function chunk<T>(arr: T[], size: number) {
    const out: T[][] = [];
    for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));
    return out;
}

function extractFunctionsError(err: unknown): string {
    if (!err) return 'Unknown error';

    // Supabase Functions errors often include context.body
    const anyErr = err as any;
    const contextBody = anyErr?.context?.body;

    if (typeof contextBody === 'string' && contextBody.trim()) {
        // sometimes it's JSON as string
        try {
            const parsed = JSON.parse(contextBody);
            return parsed?.error || parsed?.message || contextBody;
        } catch {
            return contextBody;
        }
    }

    if (typeof contextBody === 'object' && contextBody) {
        return contextBody.error || contextBody.message || anyErr.message || 'Request failed';
    }

    return anyErr.message || 'Request failed';
}

// Fetch all campaigns
export const useCampaigns = () => {
    return useQuery({
        queryKey: ['campaigns'],
        queryFn: async () => {
            const { data, error } = await supabase
                .from('campaigns')
                .select('*')
                .order('created_at', { ascending: false });

            if (error) throw error;
            return data as Campaign[];
        },
    });
};

// Create a new campaign
export const useCreateCampaign = () => {
    const queryClient = useQueryClient();
    const { user } = useAuth();

    return useMutation({
        mutationFn: async (campaign: CampaignInsert) => {
            if (!user) throw new Error('User not authenticated');

            const { data, error } = await supabase
                .from('campaigns')
                .insert({
                    ...campaign,
                    created_by: user.id,
                })
                .select()
                .single();

            if (error) throw error;
            return data as Campaign;
        },
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ['campaigns'] });
            toast.success('Campaign created successfully');
        },
        onError: (error: any) => {
            toast.error('Failed to create campaign: ' + error.message);
        },
    });
};

// Update a campaign
export const useUpdateCampaign = () => {
    const queryClient = useQueryClient();

    return useMutation({
        mutationFn: async ({ id, ...updates }: Partial<Campaign> & { id: string }) => {
            const { data, error } = await supabase
                .from('campaigns')
                .update(updates)
                .eq('id', id)
                .select()
                .single();

            if (error) throw error;
            return data as Campaign;
        },
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ['campaigns'] });
            toast.success('Campaign updated successfully');
        },
        onError: (error: any) => {
            toast.error('Failed to update campaign: ' + error.message);
        },
    });
};

// Delete a campaign
export const useDeleteCampaign = () => {
    const queryClient = useQueryClient();

    return useMutation({
        mutationFn: async (id: string) => {
            const { error } = await supabase.from('campaigns').delete().eq('id', id);
            if (error) throw error;
            return id;
        },
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ['campaigns'] });
            toast.success('Campaign deleted successfully');
        },
        onError: (error: any) => {
            toast.error('Failed to delete campaign: ' + error.message);
        },
    });
};

// Populate campaign recipients based on segment criteria
export const usePopulateCampaignRecipients = () => {
    const queryClient = useQueryClient();

    return useMutation({
        mutationFn: async ({
            campaignId,
            tagIds,
            statuses,
        }: {
            campaignId: string;
            tagIds?: string[];
            statuses?: string[];
        }) => {
            // 1) Fetch contacts (lightweight fields)
            let query = supabase.from('contacts').select('id, email').is('deleted_at', null);

            if (statuses && statuses.length > 0) {
                query = query.in('status', statuses as any);
            }

            const { data: contacts, error: contactsError } = await query;
            if (contactsError) throw contactsError;

            let eligible = contacts || [];

            // 2) Filter by tags (at least one selected tag)
            if (tagIds && tagIds.length > 0) {
                const { data: contactTags, error: tagsError } = await supabase
                    .from('contact_tags')
                    .select('contact_id')
                    .in('tag_id', tagIds);

                if (tagsError) throw tagsError;

                const taggedIds = new Set(contactTags?.map((ct) => ct.contact_id) || []);
                eligible = eligible.filter((c) => taggedIds.has(c.id));
            }

            if (eligible.length === 0) {
                throw new Error('No contacts matched this segment');
            }

            // 3) Suppression filter (query only candidate emails, chunked)
            const emails = eligible.map((c) => c.email).filter(Boolean);
            const suppressed = new Set<string>();

            for (const batch of chunk(emails, 500)) {
                const { data: suppressedRows, error: supErr } = await supabase
                    .from('suppression_list')
                    .select('email')
                    .in('email', batch);

                if (supErr) throw supErr;
                for (const row of suppressedRows || []) suppressed.add(row.email);
            }

            eligible = eligible.filter((c) => !suppressed.has(c.email));

            if (eligible.length === 0) {
                throw new Error('All matching contacts are suppressed (unsubscribed/bounced/complained)');
            }

            // 4) Replace recipients (delete then insert)
            const { error: delErr } = await supabase
                .from('campaign_recipients')
                .delete()
                .eq('campaign_id', campaignId);

            if (delErr) throw delErr;

            // Insert in chunks to avoid payload limits
            const recipientRows = eligible.map((contact) => ({
                campaign_id: campaignId,
                contact_id: contact.id,
                status: 'pending' as const,
            }));

            for (const batch of chunk(recipientRows, 500)) {
                const { error: insErr } = await supabase.from('campaign_recipients').insert(batch);
                if (insErr) throw insErr;
            }

            // 5) Update campaign totals and reset counts (so UI matches the new list)
            const { error: updErr } = await supabase
                .from('campaigns')
                .update({
                    total_recipients: recipientRows.length,
                    sent_count: 0,
                    failed_count: 0,
                    skipped_count: 0,
                    last_batch_at: null,
                    completed_at: null,
                    status: 'draft',
                })
                .eq('id', campaignId);

            if (updErr) throw updErr;

            return { count: recipientRows.length };
        },
        onSuccess: (data) => {
            queryClient.invalidateQueries({ queryKey: ['campaigns'] });
            queryClient.invalidateQueries({ queryKey: ['campaign-recipients'] });
            toast.success(`${data.count.toLocaleString()} recipients added to campaign`);
        },
        onError: (error: any) => {
            toast.error('Failed to populate recipients: ' + error.message);
        },
    });
};

// Start/activate a campaign
export const useStartCampaign = () => {
    const queryClient = useQueryClient();

    return useMutation({
        mutationFn: async (campaignId: string) => {
            const { count, error: countError } = await supabase
                .from('campaign_recipients')
                .select('*', { count: 'exact', head: true })
                .eq('campaign_id', campaignId)
                .eq('status', 'pending');

            if (countError) throw countError;
            if (!count || count === 0) {
                throw new Error('Campaign has no pending recipients');
            }

            const { data, error } = await supabase
                .from('campaigns')
                .update({ status: 'active' })
                .eq('id', campaignId)
                .select()
                .single();

            if (error) throw error;
            return data as Campaign;
        },
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ['campaigns'] });
            toast.success('Campaign activated');
        },
        onError: (error: any) => {
            toast.error('Failed to start campaign: ' + error.message);
        },
    });
};

// Send a batch of campaign emails
export const useSendCampaignBatch = () => {
    const queryClient = useQueryClient();

    return useMutation({
        mutationFn: async ({ campaignId, batchSize = 50 }: { campaignId: string; batchSize?: number }) => {
            // IMPORTANT: include Authorization header so Edge Function is not 401
            const {
                data: { session },
                error: sessionError,
            } = await supabase.auth.getSession();

            if (sessionError) throw sessionError;
            if (!session?.access_token) throw new Error('Not authenticated');

            const { data, error } = await supabase.functions.invoke('send-campaign-batch', {
                body: { campaign_id: campaignId, batch_size: batchSize },
                headers: {
                    Authorization: `Bearer ${session.access_token}`,
                },
            });

            if (error) {
                throw new Error(extractFunctionsError(error));
            }

            return data;
        },
        onSuccess: (data: any) => {
            queryClient.invalidateQueries({ queryKey: ['campaigns'] });
            queryClient.invalidateQueries({ queryKey: ['campaign-recipients'] });
            queryClient.invalidateQueries({ queryKey: ['email-logs'] });

            if (data?.status === 'completed') {
                toast.success('Campaign completed - all emails sent');
            } else if (data?.status === 'batch_complete') {
                toast.success(
                    `Batch done: ${Number(data.sent || 0)} sent, ${Number(data.failed || 0)} failed, ${Number(data.skipped || 0)} skipped`
                );
            } else if (data?.status === 'skipped') {
                toast.message(data?.reason || 'Skipped');
            }
        },
        onError: (error: any) => {
            toast.error('Failed to send batch: ' + error.message);
        },
    });
};

// Fetch campaign recipients
export const useCampaignRecipients = (campaignId: string) => {
    return useQuery({
        queryKey: ['campaign-recipients', campaignId],
        queryFn: async () => {
            const { data, error } = await supabase
                .from('campaign_recipients')
                .select(
                    `
          *,
          contacts (id, first_name, last_name, email)
        `
                )
                .eq('campaign_id', campaignId)
                .order('created_at', { ascending: true });

            if (error) throw error;
            return data;
        },
        enabled: !!campaignId,
    });
};

// Fetch email logs
export const useEmailLogs = (campaignId?: string) => {
    return useQuery({
        queryKey: ['email-logs', campaignId],
        queryFn: async () => {
            let query = supabase
                .from('email_logs')
                .select(
                    `
          *,
          contacts (id, first_name, last_name, email)
        `
                )
                .order('sent_at', { ascending: false })
                .limit(100);

            if (campaignId) query = query.eq('campaign_id', campaignId);

            const { data, error } = await query;
            if (error) throw error;
            return data;
        },
    });
};

// Fetch suppression list
export const useSuppressionList = () => {
    return useQuery({
        queryKey: ['suppression-list'],
        queryFn: async () => {
            const { data, error } = await supabase
                .from('suppression_list')
                .select('*')
                .order('created_at', { ascending: false });

            if (error) throw error;
            return data as SuppressionEntry[];
        },
    });
};

// Add to suppression list
export const useAddToSuppressionList = () => {
    const queryClient = useQueryClient();

    return useMutation({
        mutationFn: async ({ email, reason }: { email: string; reason: SuppressionEntry['reason'] }) => {
            const { data, error } = await supabase
                .from('suppression_list')
                .insert({ email, reason })
                .select()
                .single();

            if (error) throw error;
            return data;
        },
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ['suppression-list'] });
            toast.success('Email added to suppression list');
        },
        onError: (error: any) => {
            toast.error('Failed to add to suppression list: ' + error.message);
        },
    });
};

// Remove from suppression list
export const useRemoveFromSuppressionList = () => {
    const queryClient = useQueryClient();

    return useMutation({
        mutationFn: async (id: string) => {
            const { error } = await supabase.from('suppression_list').delete().eq('id', id);
            if (error) throw error;
            return id;
        },
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ['suppression-list'] });
            toast.success('Email removed from suppression list');
        },
        onError: (error: any) => {
            toast.error('Failed to remove from suppression list: ' + error.message);
        },
    });
};