import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.39.3';
import { cert, getApps, initializeApp } from 'https://esm.sh/firebase-admin@11.10.1/app?target=deno&bundle';
import { getMessaging } from 'https://esm.sh/firebase-admin@11.10.1/messaging?target=deno&bundle';

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

let supabase: ReturnType<typeof createClient> | null = null;

function getSupabase() {
  if (supabase) return supabase;
  const url = Deno.env.get('SUPABASE_URL') ?? '';
  const key = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '';
  if (!url || !key) {
    throw new Error('Missing SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY');
  }
  supabase = createClient(url, key);
  return supabase;
}

function initFirebase() {
  if (getApps().length > 0) return;
  const raw = Deno.env.get('FIREBASE_SERVICE_ACCOUNT');
  if (!raw) {
    throw new Error('Missing FIREBASE_SERVICE_ACCOUNT environment variable');
  }
  const serviceAccount = JSON.parse(raw);
  if (serviceAccount.private_key && typeof serviceAccount.private_key === 'string') {
    serviceAccount.private_key = serviceAccount.private_key.replace(/\\n/g, '\n');
  }
  initializeApp({
    credential: cert(serviceAccount),
  });
}

// Clean up invalid FCM tokens from database
async function cleanupInvalidTokens(
  supabaseClient: ReturnType<typeof createClient>,
  tokens: string[],
  responses: { success: boolean; error?: { code: string } }[]
) {
  const invalidTokens: string[] = [];

  responses.forEach((response, index) => {
    if (!response.success && response.error) {
      const errorCode = response.error.code;
      // These error codes indicate the token is no longer valid
      if (
        errorCode === 'messaging/invalid-registration-token' ||
        errorCode === 'messaging/registration-token-not-registered' ||
        errorCode === 'messaging/invalid-argument'
      ) {
        invalidTokens.push(tokens[index]);
      }
    }
  });

  if (invalidTokens.length > 0) {
    await supabaseClient
      .from('user_fcm_tokens')
      .delete()
      .in('token', invalidTokens);
    console.log(`Cleaned up ${invalidTokens.length} invalid FCM tokens`);
  }

  return invalidTokens.length;
}

Deno.serve(async (req) => {
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders });
  }

  if (req.method === 'GET') {
    const vapidKey = Deno.env.get('FIREBASE_WEB_VAPID_KEY') || '';
    return new Response(JSON.stringify({ firebase_web_vapid_key: vapidKey }), {
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    });
  }

  try {
    initFirebase();
    const supabaseClient = getSupabase();

    const payload = await req.json();
    console.log('Received payload:', JSON.stringify(payload));

    // Handle different payload formats:
    // - Database webhook: { type: 'INSERT', table: '...', record: {...} }
    // - Direct call: { conversation_id: '...', sender_id: '...' }
    // - Alternative: { new: {...} }
    const record = payload?.record ?? payload?.new ?? payload;
    console.log('Extracted record:', JSON.stringify(record));

    const conversationId = record?.conversation_id as string | undefined;
    const senderId = record?.sender_id as string | undefined;
    const messageType = record?.message_type != null
      ? Number(record.message_type)
      : undefined;

    console.log(`Processing: conversation=${conversationId}, sender=${senderId}, type=${messageType}`);

    if (!conversationId || !senderId) {
      console.error('Missing required fields in payload');
      return new Response(JSON.stringify({ error: 'Missing conversation_id or sender_id', receivedPayload: payload }), {
        status: 400,
        headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    if (messageType === 2) {
      return new Response(JSON.stringify({ skipped: true, reason: 'command_message' }), {
        headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    const { data: conversation, error: conversationError } = await supabaseClient
      .from('encrypted_conversations')
      .select('participant_a, participant_b')
      .eq('id', conversationId)
      .single();

    if (conversationError || !conversation) {
      return new Response(JSON.stringify({ error: 'Conversation not found' }), {
        status: 404,
        headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    const receiverId =
      conversation.participant_a === senderId
        ? conversation.participant_b
        : conversation.participant_a;

    if (!receiverId) {
      return new Response(JSON.stringify({ error: 'Receiver not resolved' }), {
        status: 400,
        headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    const { data: senderProfile } = await supabaseClient
      .from('profiles')
      .select('handle, display_name')
      .eq('id', senderId)
      .single();

    const senderName =
      senderProfile?.display_name?.trim() ||
      (senderProfile?.handle ? `@${senderProfile.handle}` : 'Someone');

    const { data: tokens } = await supabaseClient
      .from('user_fcm_tokens')
      .select('token')
      .eq('user_id', receiverId);

    const tokenList = (tokens ?? [])
      .map((row) => row.token as string)
      .filter((token) => !!token);

    if (tokenList.length == 0) {
      console.log(`No FCM tokens found for receiver ${receiverId}`);
      return new Response(JSON.stringify({ skipped: true, reason: 'no_tokens', receiverId }), {
        headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    console.log(`Sending to ${tokenList.length} token(s) for receiver ${receiverId}`);

    const messaging = getMessaging();
    const response = await messaging.sendEachForMulticast({
      tokens: tokenList,
      notification: {
        title: `New Message from ${senderName}`,
        body: '🔒 [Encrypted Message]',
      },
      data: {
        conversation_id: conversationId,
        type: 'chat',
      },
      // Android-specific options
      android: {
        priority: 'high',
        notification: {
          channelId: 'chat_messages',
          priority: 'high',
        },
      },
      // iOS-specific options
      apns: {
        payload: {
          aps: {
            sound: 'default',
            badge: 1,
            contentAvailable: true,
          },
        },
      },
    });

    // Clean up any invalid tokens
    const cleanedUp = await cleanupInvalidTokens(
      supabaseClient,
      tokenList,
      response.responses
    );

    console.log(`Push notification sent: ${response.successCount} success, ${response.failureCount} failed, ${cleanedUp} tokens cleaned up`);

    // Log individual failures for debugging
    response.responses.forEach((resp, index) => {
      if (!resp.success && resp.error) {
        console.error(`Failed to send to token ${index}: ${resp.error.code} - ${resp.error.message}`);
      }
    });

    return new Response(
      JSON.stringify({
        success: true,
        sent: response.successCount,
        failed: response.failureCount,
        tokensCleanedUp: cleanedUp,
      }),
      {
        headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      }
    );
  } catch (error) {
    console.error('Push notification error:', error);
    return new Response(JSON.stringify({ error: error.message ?? 'Unknown error' }), {
      status: 500,
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    });
  }
});
