<?php declare(strict_types = 1);

namespace MailPoet\Subscribers\RestApi\Endpoints;

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


use MailPoet\API\JSON\ResponseBuilders\SubscribersResponseBuilder;
use MailPoet\API\REST\AbstractListingEndpoint;
use MailPoet\Config\AccessControl;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Listing\Handler as ListingHandler;
use MailPoet\Listing\ListingDefinition;
use MailPoet\Listing\ListingRepository;
use MailPoet\Subscribers\SubscriberListingRepository;
use MailPoet\WP\Functions as WPFunctions;

class SubscribersListingEndpoint extends AbstractListingEndpoint {
  /** @var SubscriberListingRepository */
  private $subscriberListingRepository;

  /** @var SubscribersResponseBuilder */
  private $subscribersResponseBuilder;

  public function __construct(
    ListingHandler $listingHandler,
    SubscriberListingRepository $subscriberListingRepository,
    SubscribersResponseBuilder $subscribersResponseBuilder
  ) {
    parent::__construct($listingHandler);
    $this->subscriberListingRepository = $subscriberListingRepository;
    $this->subscribersResponseBuilder = $subscribersResponseBuilder;
  }

  public function checkPermissions(): bool {
    return WPFunctions::get()->currentUserCan(AccessControl::PERMISSION_MANAGE_SUBSCRIBERS);
  }

  protected function getListingRepository(): ListingRepository {
    return $this->subscriberListingRepository;
  }

  protected function getCountAndGroups(ListingRepository $repository, ListingDefinition $definition): array {
    if (!$repository instanceof SubscriberListingRepository) {
      return parent::getCountAndGroups($repository, $definition);
    }
    return $repository->getCountAndGroups($definition);
  }

  protected function buildItems(array $rows, ListingDefinition $definition): array {
    $subscribers = $this->subscribersResponseBuilder->buildForListing($rows);
    // Mirror the legacy endpoint: when filtering by a specific segment, surface
    // the per-segment unsubscribe status as the visible status so the UI shows
    // "unsubscribed from this list" rather than the global subscriber status.
    $segmentFilter = $this->extractSegmentFilter($definition);
    if ($segmentFilter !== null) {
      foreach ($subscribers as $key => $subscriber) {
        if ($this->isUnsubscribedFromSegment($subscriber, $segmentFilter)) {
          $subscribers[$key]['status'] = SubscriberEntity::STATUS_UNSUBSCRIBED;
        }
      }
    }
    return $subscribers;
  }

  protected function getDefaultSortBy(): string {
    return 'created_at';
  }

  protected function getDefaultSortOrder(): string {
    return 'desc';
  }

  protected function getDefaultGroup(): ?string {
    return 'all';
  }

  private function extractSegmentFilter(ListingDefinition $definition): ?string {
    $filters = $definition->getFilters();
    if (!isset($filters['segment']) || !is_scalar($filters['segment'])) {
      return null;
    }
    $segment = (string)$filters['segment'];
    return $segment !== '' ? $segment : null;
  }

  /**
   * @param array<string, mixed> $subscriber
   */
  private function isUnsubscribedFromSegment(array $subscriber, string $segmentId): bool {
    if (!isset($subscriber['subscriptions']) || !is_array($subscriber['subscriptions'])) {
      return false;
    }
    foreach ($subscriber['subscriptions'] as $segment) {
      if (!is_array($segment)) continue;
      if (!isset($segment['segment_id']) || !is_scalar($segment['segment_id'])) continue;
      if ((string)$segment['segment_id'] !== $segmentId) continue;
      $status = $segment['status'] ?? null;
      return is_scalar($status) && (string)$status === SubscriberEntity::STATUS_UNSUBSCRIBED;
    }
    return false;
  }
}
