import { requireAuth } from '~/server/utils/auth';
import { getCredentialsFromSession, decryptCredentials } from '~/server/utils/encryption';
import { getCachedEmails, syncEmailsWithRetry, getSyncMetadata } from '~/server/utils/email-sync';

interface EmailMessage {
  id: string;
  from: string;
  to: string | string[];
  subject: string;
  body: string;
  html?: string;
  timestamp: string;
  direction: 'sent' | 'received';
  threadId?: string;
  attachments?: any[];
}

interface EmailThread {
  id: string;
  subject: string;
  emailCount: number;
  latestTimestamp: string;
  emails: EmailMessage[];
}

export default defineEventHandler(async (event) => {
  // Check authentication (x-tag header OR Keycloak session)
  await requireAuth(event);

  try {
    const body = await readBody(event);
    const { clientEmail, interestId, sessionId } = body;

    if (!clientEmail || !sessionId || !interestId) {
      throw createError({ 
        statusCode: 400, 
        statusMessage: "Client email, interestId and sessionId are required" 
      });
    }

    // Get encrypted credentials from session
    const encryptedCredentials = getCredentialsFromSession(sessionId);
    if (!encryptedCredentials) {
      return { 
        success: true, 
        emails: [],
        threads: []
      };
    }

    // Decrypt credentials
    let userEmail: string;
    let password: string;
    
    try {
      const decrypted = decryptCredentials(encryptedCredentials);
      userEmail = decrypted.email;
      password = decrypted.password;
    } catch (decryptError) {
      console.error('[Email V2] Failed to decrypt credentials:', decryptError);
      return { 
        success: true, 
        emails: [],
        threads: []
      };
    }

    // First, get emails from MinIO cache (instant response)
    const cachedEmails = await getCachedEmails(interestId);
    
    // Get sync metadata
    const metadata = await getSyncMetadata(interestId);
    
    // Trigger background sync if not currently syncing and last sync was over 5 minutes ago
    const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
    const lastSync = new Date(metadata.lastSyncTime);
    
    if (metadata.syncStatus !== 'syncing' && lastSync < fiveMinutesAgo) {
      // Fire and forget - don't wait for sync to complete
      syncEmailsWithRetry(sessionId, userEmail, clientEmail, interestId).catch(err => {
        console.error('[Email V2] Background sync failed:', err);
      });
    }

    // Process cached emails
    const emails: EmailMessage[] = cachedEmails.map(email => ({
      id: email.id || email.messageId || `${Date.now()}-${Math.random()}`,
      from: email.from || '',
      to: email.to || '',
      subject: email.subject || '',
      body: email.body || email.text || '',
      html: email.html,
      timestamp: email.timestamp || new Date().toISOString(),
      direction: email.direction || (email.from?.toLowerCase().includes(userEmail.toLowerCase()) ? 'sent' : 'received'),
      threadId: email.threadId,
      attachments: email.attachments
    }));

    // Filter to only include emails involving the client
    const filteredEmails = emails.filter(email => {
      const fromEmail = email.from.toLowerCase();
      const toEmails = Array.isArray(email.to) ? email.to.join(' ').toLowerCase() : email.to.toLowerCase();
      
      return fromEmail.includes(clientEmail.toLowerCase()) || 
             toEmails.includes(clientEmail.toLowerCase()) ||
             fromEmail.includes(userEmail.toLowerCase()) ||
             toEmails.includes(userEmail.toLowerCase());
    });

    // Sort by timestamp (newest first)
    filteredEmails.sort((a, b) => 
      new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
    );

    // Group into threads
    const threads = groupIntoThreads(filteredEmails);

    return { 
      success: true, 
      emails: filteredEmails,
      threads: threads,
      syncStatus: metadata.syncStatus,
      lastSync: metadata.lastSyncTime,
      totalEmails: metadata.totalEmails
    };
  } catch (error) {
    console.error('[Email V2] Failed to fetch email thread:', error);
    if (error instanceof Error) {
      throw createError({ 
        statusCode: 500, 
        statusMessage: `Failed to fetch emails: ${error.message}` 
      });
    } else {
      throw createError({
        statusCode: 500,
        statusMessage: "An unexpected error occurred",
      });
    }
  }
});

// Group emails into threads based on subject and references
function groupIntoThreads(emails: EmailMessage[]): EmailThread[] {
  const threads = new Map<string, EmailMessage[]>();
  const emailById = new Map<string, EmailMessage>();
  
  // First pass: index all emails by ID
  emails.forEach(email => {
    emailById.set(email.id, email);
  });
  
  // Second pass: group emails into threads
  emails.forEach(email => {
    // Normalize subject by removing Re:, Fwd:, etc.
    const normalizedSubject = email.subject
      .replace(/^(Re:|Fwd:|Fw:|RE:|FW:|FWD:)\s*/gi, '')
      .replace(/\s+/g, ' ')
      .trim()
      .toLowerCase();
    
    // Check if this email belongs to an existing thread
    let threadFound = false;
    
    // First, check if it has a threadId (in-reply-to header)
    if (email.threadId) {
      // Look for the parent email
      const parentEmail = emailById.get(email.threadId);
      if (parentEmail) {
        // Find which thread the parent belongs to
        for (const [threadId, threadEmails] of threads.entries()) {
          if (threadEmails.some(e => e.id === parentEmail.id)) {
            threadEmails.push(email);
            threadFound = true;
            break;
          }
        }
      }
    }
    
    // If not found by threadId, try to match by subject
    if (!threadFound) {
      for (const [threadId, threadEmails] of threads.entries()) {
        const threadSubject = threadEmails[0].subject
          .replace(/^(Re:|Fwd:|Fw:|RE:|FW:|FWD:)\s*/gi, '')
          .replace(/\s+/g, ' ')
          .trim()
          .toLowerCase();
        
        if (threadSubject === normalizedSubject) {
          threadEmails.push(email);
          threadFound = true;
          break;
        }
      }
    }
    
    // If still not found, create a new thread
    if (!threadFound) {
      threads.set(email.id, [email]);
    }
  });
  
  // Convert to array format and sort emails within each thread
  return Array.from(threads.entries())
    .map(([threadId, threadEmails]) => {
      // Sort emails within thread by timestamp (oldest first for chronological order)
      threadEmails.sort((a, b) => 
        new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
      );
      
      return {
        id: threadId,
        subject: threadEmails[0].subject,
        emailCount: threadEmails.length,
        latestTimestamp: threadEmails[threadEmails.length - 1].timestamp,
        emails: threadEmails
      };
    })
    // Sort threads by latest activity (newest first)
    .sort((a, b) => new Date(b.latestTimestamp).getTime() - new Date(a.latestTimestamp).getTime());
}
