<?php declare(strict_types = 1);

namespace MailPoet\Subscription;

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


use MailPoet\Config\Renderer as TemplateRenderer;
use MailPoet\CustomFields\CustomFieldsRepository;
use MailPoet\Entities\CustomFieldEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Form\Block\Date as FormBlockDate;
use MailPoet\Form\Renderer as FormRenderer;
use MailPoet\Segments\SegmentsRepository;
use MailPoet\Settings\SettingsController;
use MailPoet\Subscribers\LinkTokens;
use MailPoet\Util\Helpers;
use MailPoet\Util\Url as UrlHelper;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Doctrine\Common\Collections\Criteria;

class ManageSubscriptionFormRenderer {
  const FORM_STATE_SUCCESS = 'success';
  const FORM_STATE_ERROR = 'error';
  const FORM_STATE_NOT_SUBMITTED = 'not_submitted';

  /** @var UrlHelper */
  private $urlHelper;

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

  /** @var LinkTokens */
  private $linkTokens;

  /** @var FormRenderer */
  private $formRenderer;

  /** @var FormBlockDate */
  private $dateBlock;

  /** @var TemplateRenderer */
  private $templateRenderer;

  /** @var CustomFieldsRepository */
  private $customFieldsRepository;

  /** @var SegmentsRepository */
  private $segmentsRepository;

  /** @var SettingsController */
  private $settings;

  public function __construct(
    WPFunctions $wp,
    UrlHelper $urlHelper,
    LinkTokens $linkTokens,
    FormRenderer $formRenderer,
    FormBlockDate $dateBlock,
    TemplateRenderer $templateRenderer,
    CustomFieldsRepository $customFieldsRepository,
    SegmentsRepository $segmentsRepository,
    SettingsController $settings
  ) {
    $this->wp = $wp;
    $this->urlHelper = $urlHelper;
    $this->linkTokens = $linkTokens;
    $this->formRenderer = $formRenderer;
    $this->dateBlock = $dateBlock;
    $this->templateRenderer = $templateRenderer;
    $this->customFieldsRepository = $customFieldsRepository;
    $this->segmentsRepository = $segmentsRepository;
    $this->settings = $settings;
  }

  public function renderForm(SubscriberEntity $subscriber, string $formState = self::FORM_STATE_NOT_SUBMITTED): string {
    $isModernStyle = $this->isModernStyle();
    $basicFields = $this->getBasicFields($subscriber, $isModernStyle);
    $customFields = $this->getCustomFields($subscriber);
    $segmentField = $this->getSegmentField($subscriber, $isModernStyle);
    $submitField = [
      'id' => 'submit',
      'type' => 'submit',
      'params' => [
        'label' => $isModernStyle ? __('Save changes', 'mailpoet') : __('Save', 'mailpoet'),
      ],
    ];

    $form = array_merge(
      $basicFields,
      $customFields,
      [
        $segmentField,
        $submitField,
      ]
    );

    $filteredForm = $this->wp->applyFilters('mailpoet_manage_subscription_page_form_fields', $form);
    if (is_array($filteredForm)) {
      $form = $filteredForm;
    }

    $templateData = [
      'actionUrl' => admin_url('admin-post.php'),
      'redirectUrl' => $this->urlHelper->getCurrentUrl(),
      'email' => $subscriber->getEmail(),
      'token' => $this->linkTokens->getToken($subscriber),
      'editEmailInfo' => __('Need to change your email address? Unsubscribe using the form below, then simply sign up again.', 'mailpoet'),
      'isModernStyle' => $isModernStyle,
      'isGloballyUnsubscribed' => $subscriber->getStatus() === SubscriberEntity::STATUS_UNSUBSCRIBED,
      'formState' => $formState,
    ];

    if ($isModernStyle) {
      $formSections = $this->splitFormSections($form);
      $templateData['identityFieldsHtml'] = $this->formRenderer->renderBlocks($formSections['identityFields'], [], null, $honeypot = false, $captcha = false);
      $templateData['additionalIdentityFieldsHtml'] = $this->formRenderer->renderBlocks($formSections['additionalIdentityFields'], [], null, $honeypot = false, $captcha = false);
      $templateData['listFieldsHtml'] = $this->formRenderer->renderBlocks($formSections['listFields'], [], null, $honeypot = false, $captcha = false);
      $templateData['submitHtml'] = $this->formRenderer->renderBlocks($formSections['submitFields'], [], null, $honeypot = false, $captcha = false);
      $templateData['hasVisibleLists'] = $formSections['hasVisibleLists'];
    } else {
      $templateData['formHtml'] = $this->formRenderer->renderBlocks($form, [], null, $honeypot = false, $captcha = false);
    }

    if ($subscriber->isWPUser() || $subscriber->getIsWoocommerceUser()) {
      $wpCurrentUser = $this->wp->wpGetCurrentUser();
      if ($wpCurrentUser->user_email === $subscriber->getEmail()) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
        $templateData['editEmailInfo'] = Helpers::replaceLinkTags(
          __('[link]Edit your profile[/link] to update your email.', 'mailpoet'),
          $this->wp->getEditProfileUrl(),
          ['target' => '_blank']
        );
      } else {
        $templateData['editEmailInfo'] = Helpers::replaceLinkTags(
          __('[link]Log in to your account[/link] to update your email.', 'mailpoet'),
          $this->wp->wpLoginUrl(),
          ['target' => '_blank']
        );
      }
    }

    return $this->templateRenderer->render('subscription/manage_subscription.html', $templateData);
  }

  private function isModernStyle(): bool {
    return $this->settings->get('subscription.manage_subscription_page_style') === SettingsController::MANAGE_SUBSCRIPTION_PAGE_STYLE_MODERN;
  }

  private function splitFormSections(array $form): array {
    $identityFields = [];
    $additionalIdentityFields = [];
    $listFields = [];
    $submitFields = [];
    $hasVisibleLists = false;
    $placeAdditionalIdentityFieldsAfterNoListNotice = false;

    foreach ($form as $field) {
      if (!is_array($field)) {
        continue;
      }
      $params = isset($field['params']) && is_array($field['params']) ? $field['params'] : [];

      if (($field['type'] ?? null) === 'submit') {
        $submitFields[] = $field;
        continue;
      }

      if (($field['type'] ?? null) === 'segment' && (($params['display_mode'] ?? null) === 'manage_subscription_choices')) {
        if (!empty($params['values']) && is_array($params['values'])) {
          $hasVisibleLists = true;
          $listFields[] = $field;
        }
        continue;
      }

      if ($placeAdditionalIdentityFieldsAfterNoListNotice) {
        $additionalIdentityFields[] = $field;
      } else {
        $identityFields[] = $field;
      }
      if (($field['id'] ?? null) === 'status') {
        $placeAdditionalIdentityFieldsAfterNoListNotice = true;
      }
    }

    return [
      'identityFields' => $identityFields,
      'additionalIdentityFields' => $additionalIdentityFields,
      'listFields' => $listFields,
      'submitFields' => $submitFields,
      'hasVisibleLists' => $hasVisibleLists,
    ];
  }

  private function getCustomFields(SubscriberEntity $subscriber): array {
    $customFieldValues = [];
    foreach ($subscriber->getSubscriberCustomFields() as $subscriberCustomField) {
      $customField = $subscriberCustomField->getCustomField();
      if (!$customField) continue;

      $customFieldValues[$customField->getId()] = $subscriberCustomField->getValue();
    }
    return array_map(function (CustomFieldEntity $customFieldEntity) use ($customFieldValues) {
      $customField = [
        'id' => 'cf_' . $customFieldEntity->getId(),
        'name' => $customFieldEntity->getName(),
        'type' => $customFieldEntity->getType(),
        'params' => $customFieldEntity->getParams(),
      ];

      $customField['params']['value'] = $customFieldValues[$customFieldEntity->getId()] ?? null;

      if ($customField['type'] === 'date') {
        $dateFormats = $this->dateBlock->getDateFormats();
        $customField['params']['date_format'] = array_shift(
          $dateFormats[$customField['params']['date_type']]
        );
      }
      if (!isset($customField['params']['label'])) {
        $customField['params']['label'] = $customField['name'];
      }

      return $customField;
    }, $this->customFieldsRepository->findAllActive());
  }

  private function getBasicFields(SubscriberEntity $subscriber, bool $isModernStyle): array {
    $statusParams = [
      'required' => true,
      'label' => $isModernStyle ? __('Email subscription status', 'mailpoet') : __('Status', 'mailpoet'),
      'values' => [
        [
          'value' => [
            SubscriberEntity::STATUS_SUBSCRIBED => __('Subscribed', 'mailpoet'),
          ],
          'is_checked' => (
            $subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED
          ),
        ],
        [
          'value' => [
            SubscriberEntity::STATUS_UNSUBSCRIBED => __('Unsubscribed', 'mailpoet'),
          ],
          'is_checked' => (
            $subscriber->getStatus() === SubscriberEntity::STATUS_UNSUBSCRIBED
          ),
        ],
        [
          'value' => [
            SubscriberEntity::STATUS_BOUNCED => __('Bounced', 'mailpoet'),
          ],
          'is_checked' => (
            $subscriber->getStatus() === SubscriberEntity::STATUS_BOUNCED
          ),
          'is_disabled' => true,
          'is_hidden' => (
            $subscriber->getStatus() !== SubscriberEntity::STATUS_BOUNCED
          ),
        ],
        [
          'value' => [
            SubscriberEntity::STATUS_INACTIVE => __('Inactive', 'mailpoet'),
          ],
          'is_checked' => (
            $subscriber->getStatus() === SubscriberEntity::STATUS_INACTIVE
          ),
          'is_hidden' => (
            $subscriber->getStatus() !== SubscriberEntity::STATUS_INACTIVE
          ),
        ],
      ],
    ];
    if ($isModernStyle) {
      $statusParams['description'] = __('This controls whether you receive emails overall. Your list choices below control which public lists you receive.', 'mailpoet');
      $statusParams['class_name'] = 'mailpoet-manage-subscription-status';
      $statusParams['input_id'] = 'mailpoet_manage_subscription_status';
    }

    return [
      [
        'id' => 'first_name',
        'type' => 'text',
        'params' => [
          'label' => __('First name', 'mailpoet'),
          'value' => $subscriber->getFirstName(),
          'disabled' => ($subscriber->isWPUser() || $subscriber->getIsWoocommerceUser()),
        ],
      ],
      [
        'id' => 'last_name',
        'type' => 'text',
        'params' => [
          'label' => __('Last name', 'mailpoet'),
          'value' => $subscriber->getLastName(),
          'disabled' => ($subscriber->isWPUser() || $subscriber->getIsWoocommerceUser()),
        ],
      ],
      [
        'id' => 'status',
        'type' => 'select',
        'params' => $statusParams,
      ],
    ];
  }

  private function getSegmentField(SubscriberEntity $subscriber, bool $isModernStyle): array {
    // Get default segments
    $criteria = [
      'type' => SegmentEntity::TYPE_DEFAULT,
      'deletedAt' => null,
      'displayInManageSubscriptionPage' => true,
    ];
    $segments = $this->segmentsRepository->findBy($criteria, ['name' => Criteria::ASC]);

    $subscribedSegmentIds = [];
    foreach ($subscriber->getSubscriberSegments() as $subscriberSegment) {
      $segment = $subscriberSegment->getSegment();
      if (!$segment) continue;

      if ($subscriberSegment->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED) {
        $subscribedSegmentIds[] = $segment->getId();
      }
    }

    $segments = array_map(function (SegmentEntity $segment) use ($subscribedSegmentIds, $isModernStyle) {
      $segmentData = [
        'id' => $segment->getId(),
        'name' => $segment->getName(),
        'is_checked' => in_array($segment->getId(), $subscribedSegmentIds),
      ];
      if ($isModernStyle) {
        $segmentData['public_description'] = $segment->getPublicDescription();
      }
      return $segmentData;
    }, $segments);

    $params = [
      'label' => __('Your lists', 'mailpoet'),
      'class_name' => 'mailpoet-manage-subscription-list-fields',
      'values' => $segments,
    ];
    if ($isModernStyle) {
      $params['description'] = __('Choose Yes for lists you want to receive and No for lists you do not want to receive.', 'mailpoet');
      $params['display_mode'] = 'manage_subscription_choices';
    }

    return [
      'id' => 'segments',
      'type' => 'segment',
      'params' => $params,
    ];
  }
}