/**
 * @ai-summary Controller for Resend inbound email webhook and user-facing pending association endpoints
 * @ai-context Webhook handler (public) + pending association CRUD (JWT-authenticated)
 */

import { FastifyRequest, FastifyReply } from 'fastify';
import { ResendInboundClient } from '../external/resend-inbound.client';
import { EmailIngestionRepository } from '../data/email-ingestion.repository';
import { EmailIngestionService } from '../domain/email-ingestion.service';
import { logger } from '../../../core/logging/logger';
import type { ResendWebhookEvent } from '../domain/email-ingestion.types';

export class EmailIngestionController {
  private resendClient: ResendInboundClient;
  private repository: EmailIngestionRepository;
  private service: EmailIngestionService;

  constructor() {
    this.resendClient = new ResendInboundClient();
    this.repository = new EmailIngestionRepository();
    this.service = new EmailIngestionService();
  }

  // ========================
  // Pending Association Endpoints (JWT-authenticated)
  // ========================

  async getPendingAssociations(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    try {
      const userId = (request as any).user.sub;
      const associations = await this.repository.getPendingAssociations(userId);
      return reply.code(200).send(associations);
    } catch (error: any) {
      logger.error('Error listing pending associations', { error: error.message, userId: (request as any).user?.sub });
      return reply.code(500).send({ error: 'Failed to list pending associations' });
    }
  }

  async getPendingAssociationCount(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    try {
      const userId = (request as any).user.sub;
      const count = await this.repository.getPendingAssociationCount(userId);
      return reply.code(200).send({ count });
    } catch (error: any) {
      logger.error('Error counting pending associations', { error: error.message, userId: (request as any).user?.sub });
      return reply.code(500).send({ error: 'Failed to count pending associations' });
    }
  }

  async resolveAssociation(
    request: FastifyRequest<{ Params: { id: string }; Body: { vehicleId: string } }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const userId = (request as any).user.sub;
      const { id } = request.params;
      const { vehicleId } = request.body;

      if (!vehicleId || typeof vehicleId !== 'string') {
        return reply.code(400).send({ error: 'vehicleId is required' });
      }

      const result = await this.service.resolveAssociation(id, vehicleId, userId);
      return reply.code(200).send(result);
    } catch (error: any) {
      const userId = (request as any).user?.sub;
      logger.error('Error resolving pending association', {
        error: error.message,
        associationId: request.params.id,
        userId,
      });

      if (error.message === 'Pending association not found' || error.message === 'Vehicle not found') {
        return reply.code(404).send({ error: error.message });
      }
      if (error.message === 'Unauthorized') {
        return reply.code(403).send({ error: 'Not authorized' });
      }
      if (error.message === 'Association already resolved') {
        return reply.code(409).send({ error: error.message });
      }

      return reply.code(500).send({ error: 'Failed to resolve association' });
    }
  }

  async dismissAssociation(
    request: FastifyRequest<{ Params: { id: string } }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const userId = (request as any).user.sub;
      const { id } = request.params;

      await this.service.dismissAssociation(id, userId);
      return reply.code(204).send();
    } catch (error: any) {
      const userId = (request as any).user?.sub;
      logger.error('Error dismissing pending association', {
        error: error.message,
        associationId: request.params.id,
        userId,
      });

      if (error.message === 'Pending association not found') {
        return reply.code(404).send({ error: error.message });
      }
      if (error.message === 'Unauthorized') {
        return reply.code(403).send({ error: 'Not authorized' });
      }
      if (error.message === 'Association already resolved') {
        return reply.code(409).send({ error: error.message });
      }

      return reply.code(500).send({ error: 'Failed to dismiss association' });
    }
  }

  // ========================
  // Webhook Endpoint (Public)
  // ========================

  async handleInboundWebhook(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    try {
      const rawBody = (request as any).rawBody;
      if (!rawBody) {
        logger.error('Missing raw body in Resend webhook request');
        return reply.status(400).send({ error: 'Missing raw body' });
      }

      // Extract Svix headers for signature verification
      const headers: Record<string, string> = {
        'svix-id': (request.headers['svix-id'] as string) || '',
        'svix-timestamp': (request.headers['svix-timestamp'] as string) || '',
        'svix-signature': (request.headers['svix-signature'] as string) || '',
      };

      // Verify webhook signature
      let event: ResendWebhookEvent;
      try {
        event = this.resendClient.verifyWebhookSignature(rawBody, headers);
      } catch (error: any) {
        logger.warn('Invalid Resend webhook signature', { error: error.message });
        return reply.status(400).send({ error: 'Invalid signature' });
      }

      const emailId = event.data.email_id;
      const senderEmail = event.data.from;

      // Idempotency check: reject if email_id already exists in queue
      const existing = await this.repository.findByEmailId(emailId);
      if (existing) {
        logger.info('Duplicate email webhook received, skipping', { emailId });
        return reply.status(200).send({ received: true, duplicate: true });
      }

      // Insert queue record with status=pending via repository
      await this.repository.insertQueueEntry({
        emailId,
        senderEmail,
        userId: senderEmail, // Resolved to auth0_sub during processing
        receivedAt: event.data.created_at || new Date().toISOString(),
        subject: event.data.subject,
      });

      logger.info('Inbound email queued for processing', { emailId, senderEmail });

      // Return 200 immediately before processing begins
      reply.status(200).send({ received: true });

      // Trigger async processing via setImmediate
      setImmediate(() => {
        this.service.processEmail(emailId, event).catch((error) => {
          logger.error('Async email processing failed', {
            emailId,
            error: error instanceof Error ? error.message : String(error),
          });
        });
      });
    } catch (error: any) {
      logger.error('Resend webhook handler error', {
        error: error.message,
        stack: error.stack,
      });
      return reply.status(500).send({ error: 'Webhook processing failed' });
    }
  }
}
