import { Sender } from "@prisma/client";
import { AppError } from "@/core/errors/app-error";
import { SuppressedEmailsRepository } from "@/modules/suppression/repositories/suppressed-emails-repository";
import { buildEmailContent } from "../entities/build-email-content";
import { MailProvider } from "../providers/mail-provider";
import { CampaignLogsRepository } from "../repositories/campaign-logs-repository";

interface ResendCampaignToContactUseCaseRequest {
  logId: string;
  contactId: string;
  userId: string;
}

interface ResendCampaignToContactUseCaseResponse {
  success: true;
  messageId?: string;
}

/**
 * Reenvia pontualmente, para um único contato, o mesmo envio (`CampaignLog`) já feito por uma
 * campanha — acionado pelo painel de histórico de e-mails do contato. Reaproveita o mesmo log
 * (via `incrementRetryCount` + `markSuccess`/`markFailed`, igual ao `retry-failed-campaign`) em
 * vez de criar um novo, já que `[campaignId, contactId]` é único — isso preserva o histórico de
 * aberturas/cliques anteriores e mantém estável o token do pixel de rastreamento.
 */
export class ResendCampaignToContactUseCase {
  constructor(
    private campaignLogsRepository: CampaignLogsRepository,
    private suppressedEmailsRepository: SuppressedEmailsRepository,
    private mailProviderFactory: (sender: Sender) => MailProvider
  ) {}

  async execute({
    logId,
    contactId,
    userId,
  }: ResendCampaignToContactUseCaseRequest): Promise<ResendCampaignToContactUseCaseResponse> {
    const log = await this.campaignLogsRepository.findByIdWithCampaignAndContact(logId);

    if (!log || log.campaign.createdById !== userId || log.contactId !== contactId) {
      throw AppError.notFound("Envio não encontrado");
    }

    if (log.contact.status !== "ACTIVE") {
      throw AppError.badRequest(
        "Não é possível reenviar para um contato inativo, descadastrado ou com bounce."
      );
    }

    if (await this.suppressedEmailsRepository.isSuppressed(log.contact.email)) {
      throw AppError.badRequest("E-mail suprimido (bounce ou reclamação anterior)");
    }

    await this.campaignLogsRepository.incrementRetryCount(log.id);

    const mailProvider = this.mailProviderFactory(log.campaign.sender);
    const trackingToken = log.campaign.sender.provider === "SES" ? undefined : log.id;
    const content = buildEmailContent(log.campaign.htmlBody, log.contact.id, trackingToken);

    const result = await mailProvider.send({
      sender: log.campaign.sender,
      to: log.contact.email,
      subject: log.campaign.subject,
      html: content.html,
      text: content.text,
      headers: content.headers,
    });

    if (result.success) {
      await this.campaignLogsRepository.markSuccess(log.id);
      if (result.messageId) {
        await this.campaignLogsRepository.updateMessageId(log.id, result.messageId);
      }
      return { success: true, messageId: result.messageId };
    }

    await this.campaignLogsRepository.markFailed(
      log.id,
      result.errorMessage ?? "Erro desconhecido ao enviar e-mail"
    );
    throw AppError.badRequest(result.errorMessage ?? "Não foi possível reenviar o e-mail");
  }
}
