<?php declare(strict_types = 1);

namespace MailPoet\Statistics;

if (!defined('ABSPATH')) exit;


use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Entities\StatisticsUnsubscribeEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
use MailPoet\WP\Functions as WPFunctions;

class UnsubscribeReasonTracker {
  const MAX_REASON_TEXT_LENGTH = 500;

  /** @var SendingQueuesRepository */
  private $sendingQueuesRepository;

  /** @var StatisticsUnsubscribesRepository */
  private $statisticsUnsubscribesRepository;

  /** @var WPFunctions */
  private $wp;

  public function __construct(
    SendingQueuesRepository $sendingQueuesRepository,
    StatisticsUnsubscribesRepository $statisticsUnsubscribesRepository,
    WPFunctions $wp
  ) {
    $this->sendingQueuesRepository = $sendingQueuesRepository;
    $this->statisticsUnsubscribesRepository = $statisticsUnsubscribesRepository;
    $this->wp = $wp;
  }

  /**
   * @return array<string, string>
   */
  public function getReasonLabels(): array {
    return [
      StatisticsUnsubscribeEntity::REASON_NO_LONGER_INTERESTED => __('I no longer want to receive these emails', 'mailpoet'),
      StatisticsUnsubscribeEntity::REASON_DID_NOT_SIGN_UP => __('I never signed up for this mailing list', 'mailpoet'),
      StatisticsUnsubscribeEntity::REASON_INAPPROPRIATE_CONTENT => __('The emails are inappropriate', 'mailpoet'),
      StatisticsUnsubscribeEntity::REASON_SPAM => __('The emails are spam and should be reported', 'mailpoet'),
      StatisticsUnsubscribeEntity::REASON_OTHER => __('Other', 'mailpoet'),
    ];
  }

  public function isValidReason(string $reason): bool {
    return in_array($reason, StatisticsUnsubscribeEntity::REASONS, true);
  }

  public function findTargetUnsubscribe(SubscriberEntity $subscriber, ?int $queueId): ?StatisticsUnsubscribeEntity {
    if ($queueId !== null) {
      $queue = $this->sendingQueuesRepository->findOneById($queueId);
      if (!$queue instanceof SendingQueueEntity) {
        return null;
      }
      $newsletter = $queue->getNewsletter();
      if (!$newsletter instanceof NewsletterEntity) {
        return null;
      }
      return $this->statisticsUnsubscribesRepository->findOneBySubscriberAndQueue($subscriber, $queue, $newsletter);
    }

    return $this->statisticsUnsubscribesRepository->findLatestForSubscriber($subscriber);
  }

  public function saveReason(
    SubscriberEntity $subscriber,
    ?int $queueId,
    string $reason,
    ?string $reasonText,
    bool $allowOtherText
  ): ?StatisticsUnsubscribeEntity {
    if (!$this->isValidReason($reason)) {
      return null;
    }

    $unsubscribe = $this->findTargetUnsubscribe($subscriber, $queueId);
    if (!$unsubscribe instanceof StatisticsUnsubscribeEntity) {
      return null;
    }

    $unsubscribe->setReasonData($reason, $this->prepareReasonText($reason, $reasonText, $allowOtherText));
    $this->statisticsUnsubscribesRepository->persist($unsubscribe);
    $this->statisticsUnsubscribesRepository->flush();

    return $unsubscribe;
  }

  private function prepareReasonText(string $reason, ?string $reasonText, bool $allowOtherText): ?string {
    if (!$allowOtherText || $reason !== StatisticsUnsubscribeEntity::REASON_OTHER || $reasonText === null) {
      return null;
    }

    $reasonText = $this->wp->wpStripAllTags($reasonText, true);
    $reasonText = trim($reasonText);
    if ($reasonText === '') {
      return null;
    }

    return function_exists('mb_substr')
      ? mb_substr($reasonText, 0, self::MAX_REASON_TEXT_LENGTH)
      : substr($reasonText, 0, self::MAX_REASON_TEXT_LENGTH);
  }
}
