import { ContactStatus, EmailEventType, SuppressionReason } from "@prisma/client";
import { sesEventSchema } from "../dtos/ses-event-schema";
import { EmailEventsRepository } from "../repositories/email-events-repository";
import { SesSuppressionProvider } from "../providers/ses-suppression-provider";
import { CampaignLogsRepository } from "@/modules/campaigns/repositories/campaign-logs-repository";
import { ContactsRepository } from "@/modules/contacts/repositories/contacts-repository";
import { SuppressedEmailsRepository } from "@/modules/suppression/repositories/suppressed-emails-repository";

interface HandleSesNotificationUseCaseRequest {
  rawMessage: unknown;
}

export class HandleSesNotificationUseCase {
  constructor(
    private campaignLogsRepository: CampaignLogsRepository,
    private contactsRepository: ContactsRepository,
    private suppressedEmailsRepository: SuppressedEmailsRepository,
    private emailEventsRepository: EmailEventsRepository,
    private sesSuppressionProvider: SesSuppressionProvider
  ) {}

  async execute({ rawMessage }: HandleSesNotificationUseCaseRequest): Promise<void> {
    const parsed = sesEventSchema.safeParse(rawMessage);
    if (!parsed.success) {
      return;
    }

    const event = parsed.data;
    const log = await this.campaignLogsRepository.findByMessageId(event.mail.messageId);

    const eventType = event.eventType.toUpperCase() as EmailEventType;

    await this.emailEventsRepository.create({
      type: eventType,
      messageId: event.mail.messageId,
      campaignId: log?.campaignId ?? null,
      contactId: log?.contactId ?? null,
      payload: rawMessage,
    });

    if (event.eventType === "Bounce" && event.bounce) {
      const isPermanent = event.bounce.bounceType === "Permanent";

      for (const recipient of event.bounce.bouncedRecipients) {
        await this.suppressEmail(recipient.emailAddress, "BOUNCE", "ses-webhook");
      }

      if (log && isPermanent) {
        await this.campaignLogsRepository.markFailed(log.id, "Bounce permanente reportado pelo SES");
        await this.contactsRepository.updateStatus(log.contactId, ContactStatus.BOUNCED);
      }
      return;
    }

    if (event.eventType === "Complaint" && event.complaint) {
      for (const recipient of event.complaint.complainedRecipients) {
        await this.suppressEmail(recipient.emailAddress, "COMPLAINT", "ses-webhook");
      }

      if (log) {
        await this.contactsRepository.updateStatus(log.contactId, ContactStatus.UNSUBSCRIBED);
      }
    }
  }

  private async suppressEmail(
    email: string,
    reason: "BOUNCE" | "COMPLAINT",
    source: string
  ): Promise<void> {
    await this.suppressedEmailsRepository.add(email, SuppressionReason[reason], source);
    await this.sesSuppressionProvider.putSuppressedDestination(email, reason);
  }
}
