import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
import { corsHeaders } from '../_shared/cors.ts';
import { createEdgeFunction, type EdgeFunctionContext } from '../_shared/edgeFunctionWrapper.ts';
import { addSpanEvent } from '../_shared/logger.ts';

interface InboundEmailPayload {
  from: string;
  to: string;
  subject: string;
  text: string;
  html?: string;
  messageId: string;
  inReplyTo?: string;
  references?: string[];
  headers: Record<string, string>;
}

const handler = async (req: Request, { supabase, span, requestId }: EdgeFunctionContext): Promise<Response> => {
  const payload: InboundEmailPayload = await req.json();
  const { from, to, subject, text, html, messageId, inReplyTo, references, headers } = payload;

  addSpanEvent(span, 'email_received', {
    from,
    to,
    messageId,
    hasInReplyTo: !!inReplyTo
  });

  // Extract thread ID from headers or inReplyTo
  let threadId = headers['X-Thread-ID'] || 
                 (inReplyTo ? inReplyTo.replace(/<|>/g, '').split('@')[0] : null);

  // If no thread ID, this is a NEW direct email (not a reply)
  const isNewEmail = !threadId;

  if (isNewEmail) {
    addSpanEvent(span, 'new_direct_email', { from, subject });
  }

  // Find or create submission
  let submission = null;

  if (isNewEmail) {
    // Extract sender email
    const senderEmail = from.match(/<(.+)>/)?.[1] || from;
    const senderName = from.match(/^(.+?)\s*</)?.[1]?.trim() || senderEmail.split('@')[0];
    
    // Check for existing submission from this email in last 5 minutes (avoid duplicates)
    const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString();
    const { data: existingRecent } = await supabase
      .from('contact_submissions')
      .select('id, ticket_number, thread_id, email')
      .eq('email', senderEmail.toLowerCase())
      .eq('subject', subject || '(No Subject)')
      .gte('created_at', fiveMinutesAgo)
      .maybeSingle();
    
    if (existingRecent) {
      // Use existing recent submission (duplicate email)
      submission = existingRecent;
      threadId = existingRecent.thread_id;
      
      addSpanEvent(span, 'duplicate_submission_found', {
        submissionId: existingRecent.id,
        ticketNumber: existingRecent.ticket_number
      });
    } else {
      // Create new contact submission
      const { data: newSubmission, error: createError } = await supabase
        .from('contact_submissions')
        .insert({
          name: senderName,
          email: senderEmail.toLowerCase(),
          subject: subject || '(No Subject)',
          message: text || html || '(Empty message)',
          category: 'general',
          status: 'pending',
          user_agent: 'Email Client',
          ip_address_hash: null
        })
        .select('id, ticket_number, email, status')
        .single();
      
      if (createError || !newSubmission) {
        addSpanEvent(span, 'submission_creation_failed', { error: createError });
        throw createError;
      }
      
      submission = newSubmission;
      threadId = `${newSubmission.ticket_number}.${newSubmission.id}`;
      
      // Update thread_id
      await supabase
        .from('contact_submissions')
        .update({ thread_id: threadId })
        .eq('id', newSubmission.id);
      
      addSpanEvent(span, 'submission_created', {
        submissionId: newSubmission.id,
        ticketNumber: newSubmission.ticket_number,
        threadId
      });
    }
  } else {
    // Find submission by thread_id or ticket_number
    const ticketMatch = threadId.match(/(?:ticket-)?(TW-\d+)/i);
    const ticketNumber = ticketMatch ? ticketMatch[1] : null;

    addSpanEvent(span, 'thread_lookup', { threadId, ticketNumber });

    // Strategy 1: Try exact thread_id match
    const { data: submissionByThreadId } = await supabase
      .from('contact_submissions')
      .select('id, email, status, ticket_number')
      .eq('thread_id', threadId)
      .maybeSingle();

    if (submissionByThreadId) {
      submission = submissionByThreadId;
      addSpanEvent(span, 'submission_found_by_thread_id', { submissionId: submission.id });
    } else if (ticketNumber) {
      // Strategy 2: Try ticket_number match
      const { data: submissionByTicket, error: error2 } = await supabase
        .from('contact_submissions')
        .select('id, email, status, ticket_number, thread_id')
        .eq('ticket_number', ticketNumber)
        .maybeSingle();
      
      if (submissionByTicket) {
        submission = submissionByTicket;
        
        // Update thread_id if it's null or in old format
        if (!submissionByTicket.thread_id || submissionByTicket.thread_id !== threadId) {
          await supabase
            .from('contact_submissions')
            .update({ thread_id: threadId })
            .eq('id', submissionByTicket.id);
          
          addSpanEvent(span, 'thread_id_updated', {
            submissionId: submissionByTicket.id,
            oldThreadId: submissionByTicket.thread_id,
            newThreadId: threadId
          });
        }
        
        addSpanEvent(span, 'submission_found_by_ticket_number', { submissionId: submission.id });
      } else {
        addSpanEvent(span, 'submission_not_found', { threadId, ticketNumber });
        return new Response(JSON.stringify({ success: false, reason: 'submission_not_found' }), {
          status: 200,
          headers: { 'Content-Type': 'application/json' }
        });
      }
    } else {
      addSpanEvent(span, 'submission_not_found', { threadId });
      return new Response(JSON.stringify({ success: false, reason: 'submission_not_found' }), {
        status: 200,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    // Verify sender email matches (only for existing submissions)
    const senderEmail = from.match(/<(.+)>/)?.[1] || from;
    if (senderEmail.toLowerCase() !== submission.email.toLowerCase()) {
      addSpanEvent(span, 'email_mismatch', {
        expected: submission.email,
        received: senderEmail
      });
      return new Response(JSON.stringify({ success: false, reason: 'email_mismatch' }), {
        status: 200,
        headers: { 'Content-Type': 'application/json' }
      });
    }
  }

  // Insert email thread record
  const senderEmail = from.match(/<(.+)>/)?.[1] || from;
  const { error: insertError } = await supabase
    .from('contact_email_threads')
    .insert({
      submission_id: submission.id,
      message_id: messageId,
      in_reply_to: inReplyTo || null,
      reference_chain: references || [],
      from_email: senderEmail,
      to_email: to,
      subject,
      body_text: text,
      body_html: html,
      direction: 'inbound',
      metadata: {
        received_at: new Date().toISOString(),
        headers: headers,
        is_new_ticket: isNewEmail
      }
    });

  if (insertError) {
    addSpanEvent(span, 'thread_insert_failed', { error: insertError });
    throw insertError;
  }

  addSpanEvent(span, 'thread_inserted');

  // Update submission status if pending
  if (submission.status === 'pending') {
    await supabase
      .from('contact_submissions')
      .update({ status: 'in_progress' })
      .eq('id', submission.id);
    
    addSpanEvent(span, 'status_updated', { newStatus: 'in_progress' });
  }

  addSpanEvent(span, 'email_processed', { submissionId: submission.id });

  return new Response(
    JSON.stringify({ success: true }),
    { status: 200, headers: { 'Content-Type': 'application/json' } }
  );
};

serve(createEdgeFunction({
  name: 'receive-inbound-email',
  requireAuth: false,
  useServiceRole: true,
  corsHeaders,
  logRequests: true,
  logResponses: true,
}, handler));
