<?php

namespace MDirectorNewsletter\admin;

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

use MDirectorNewsletter\includes\Mdirector_Newsletter_Twig;
use MDirectorNewsletter\includes\Mdirector_Newsletter_Utils;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\TemplateWrapper;

require_once(plugin_dir_path(__FILE__) . '../vendor/autoload.php');

class MDirector_Newsletter_Scheduler
{
    const MDIRECTOR_SCHEDULER_NONCE_FIELD = 'mdirector_scheduler_nonce';
    const MDIRECTOR_SCHEDULER_ACTIVE_FIELD = 'mdirector_scheduler_active';
    const MDIRECTOR_SCHEDULER_TEMPLATE_FIELD = 'mdirector-scheduler-template';
    const MDIRECTOR_SCHEDULER_FROM_FIELD = 'mdirector-scheduler-from';
    const MDIRECTOR_SCHEDULER_SUBJECT_FIELD = 'mdirector-scheduler-subject';
    const MDIRECTOR_SCHEDULER_LISTS_FIELD = 'mdirector-scheduler-lists';
    const MDIRECTOR_SCHEDULER_SEGMENTS_FIELD = 'mdirector-scheduler-segments';
    const MDIRECTOR_SCHEDULER_GROUPS_FIELD = 'mdirector-scheduler-groups';
    const MDIRECTOR_SCHEDULER_CAMPAIGN_FIELD = 'mdirector-scheduler-campaign';
    const MDIRECTOR_SCHEDULER_DELIVERY_FIELD = 'mdirector-scheduler-delivery';
    const MDIRECTOR_SCHEDULER_PREVIEW_FIELD = 'mdirector-scheduler-preview';
    const MDIRECTOR_SCHEDULER_SEND_FIELD = 'mdirector-scheduler-send';
    const MDIRECTOR_ALREADY_SENT = 'mdirector-already-sent';

    const PREVIEW_MODE_ON = true;
    const PREVIEW_MODE_OFF = false;
    const DEFAULT_PRIORITY = 'default';
    const POST_PUBLISHED = 'publish';
    const AUTO_DRAFT_STATUS = 'auto-draft';
    /**
     * @var \Twig\TemplateWrapper
     */
    protected $adminTemplate;
    protected $sendMode = false;
    private $postID;
    /**
     * @var Mdirector_Newsletter_Twig
     */
    private $twigInstance;
    /**
     * @var Mdirector_Newsletter_Utils
     */
    private $MDirectorUtils;

    public function __construct()
    {
        $this->loadDependencies();

        $this->MDirectorUtils = new Mdirector_Newsletter_Utils();

        $this->twigInstance = new Mdirector_Newsletter_Twig();
        $this->adminTemplate = $this->twigInstance->initAdminTemplate();

        add_action('add_meta_boxes', [$this, 'mdirectorScheduler']);
        add_action('save_post', [$this, 'mdirectorSchedulerData']);
        add_action('transition_post_status', [$this, 'newPostTrigger'], 10, 3);

        add_filter('rest_pre_insert_post', function ($prepared_post, $request) {
            $metaData = $request->get_param('meta');

            if (!empty($metaData)) {
                foreach ($metaData as $key => $value) {
                    if (
                        ($key === 'mdirector-scheduler-send') &&
                        ($value === 'mdirector-scheduler-send')
                    ) {
                        update_post_meta($prepared_post->ID, self::MDIRECTOR_ALREADY_SENT, 'false');
                        $this->sendMode = true;
                        continue;
                    }
                    update_post_meta($prepared_post->ID, $key, $value);
                }
            }

            return $prepared_post;
        }, 10, 2);
    }

    private function loadDependencies()
    {
    }

    public function mdirectorScheduler()
    {
        add_meta_box(
            'mdirector_scheduler_delivery_id',
            __( 'MDSCHEDULER__TITLE', 'emblue-newsletter' ),
            [$this, 'MDSchedulerWidget'],
            $this->getSchedulerTaxonomies(),
            'side',
            self::DEFAULT_PRIORITY
        );
    }

    private function getPostTypeLabel( $postType ) {
        $labels = [
            'post'       => __( 'MDSCHEDULER__POST__TYPE--POST', 'emblue-newsletter' ),
            'page'       => __( 'MDSCHEDULER__POST__TYPE--PAGE', 'emblue-newsletter' ),
            'auto-draft' => __( 'MDSCHEDULER__POST__TYPE--AUTO-DRAFT', 'emblue-newsletter' ),
        ];
        return $labels[ strtolower( $postType ) ] ?? strtoupper( $postType );
    }

    private function getSchedulerTaxonomies()
    {
        $options = $this->MDirectorUtils->getPluginOptions();
        $output = [];
        $taxonomies = [];

        if (isset($options['mdirector_scheduler_posts']) &&
            $options['mdirector_scheduler_posts'] === Mdirector_Newsletter_Utils::SETTINGS_OPTION_ON) {
            $output[] = 'post';
        }

        if (isset($options['mdirector_scheduler_taxonomies']) &&
            !empty($options['mdirector_scheduler_taxonomies'])) {
            $taxonomies = array_map('trim', explode(',', $options['mdirector_scheduler_taxonomies']));
        }

        return array_unique(array_merge($output, $taxonomies));
    }

    public function MDSchedulerWidget()
    {
        $this->postID = get_post()->ID;
        $title = get_post()->post_title;
        $from = $this->getDefaultSchedulerFrom();
        $active = $this->isSchedulerActive();
        $templates = $this->getUserTemplates();
        $campaigns = $this->getUserCampaigns();
        $userLists = $this->getUserLists();

        wp_nonce_field(plugin_basename(__FILE__), self::MDIRECTOR_SCHEDULER_NONCE_FIELD);

        $templateData = [
            'mdSchedulerActiveField' => self::MDIRECTOR_SCHEDULER_ACTIVE_FIELD,
            'mdSchedulerActive' => $active,
            'mdSchedulerFromField' => self::MDIRECTOR_SCHEDULER_FROM_FIELD,
            'mdSchedulerFromFieldValue' => $this->getMetaValue(self::MDIRECTOR_SCHEDULER_FROM_FIELD) ?: $from,
            'mdSchedulerSubjectField' => self::MDIRECTOR_SCHEDULER_SUBJECT_FIELD,
            'mdSchedulerSubjectFieldValue' => $this->getMetaValue(self::MDIRECTOR_SCHEDULER_SUBJECT_FIELD) ?: $title,
            'mdSchedulerSubjectFieldPlaceholder' => $title,
            'mdSchedulerTemplateField' => self::MDIRECTOR_SCHEDULER_TEMPLATE_FIELD,
            'mdSchedulerTemplateHTML' => $templates,
            'mdSchedulerCampaignField' => self::MDIRECTOR_SCHEDULER_CAMPAIGN_FIELD,
            'mdSchedulerCampaignHTLM' => $campaigns,
            'mdSchedulerDeliveryField' => self::MDIRECTOR_SCHEDULER_DELIVERY_FIELD,
            'mdSchedulerDeliveryFieldValue' => $this->getMetaValue(self::MDIRECTOR_SCHEDULER_DELIVERY_FIELD) ?: $title,
            'mdSchedulerLists' => $userLists,
            'mdSchedulerPreviewField' => self::MDIRECTOR_SCHEDULER_PREVIEW_FIELD,
            'mdSchedulerSendField' => self::MDIRECTOR_SCHEDULER_SEND_FIELD,
            'postType' => $this->getPostTypeLabel( get_post_type( $this->postID ) ),
        ];

        $template = $this->isSchedulerEnabled() ? 'MDSchedulerEnabled' : 'MDSchedulerDisabled';

        echo wp_kses( $this->adminTemplate->renderBlock( $template, $templateData ), Mdirector_Newsletter_Utils::allowedHtml() );
    }

    private function getDefaultSchedulerFrom()
    {
        $from = $this->getPluginOption('mdirector_scheduler_default_from_name');

        return !empty($from)
            ? $from
            : '';
    }

    private function getPluginOption($option)
    {
        $options = get_option('mdirector_settings') ?: [];

        return isset($options[$option])
            ? $options[$option]
            : null;
    }

    private function isSchedulerActive()
    {
        $metas = get_post_meta($this->postID);

        return isset($metas[self::MDIRECTOR_SCHEDULER_ACTIVE_FIELD][0])
            ? $metas[self::MDIRECTOR_SCHEDULER_ACTIVE_FIELD][0]
            : '0';
    }

    private function getUserTemplates()
    {
        $availableTemplates = $this->MDirectorUtils->getPluginTemplates();
        $currentTemplateSelected = $this->getMetaValue(self::MDIRECTOR_SCHEDULER_TEMPLATE_FIELD);

        return $this->MDirectorUtils->getTemplateOptionsHTML($availableTemplates, $currentTemplateSelected);
    }

    private function getMetaValue($field)
    {
        $metas = get_post_meta($this->postID);

        return isset($metas[$field][0])
            ? $metas[$field][0]
            : '';
    }

    private function getUserCampaigns()
    {
        $availableCampaigns = $this->MDirectorUtils->getUserCampaignsByAPI();
        $currentCampaignSelected = $this->getMetaValue(self::MDIRECTOR_SCHEDULER_CAMPAIGN_FIELD);

        return $this->MDirectorUtils->getUserCampaignsHTML($availableCampaigns, $currentCampaignSelected);
    }

    /**
     * @return string
     */
    private function getUserLists()
    {
        $currentListsSelected = unserialize($this->getMetaValue(self::MDIRECTOR_SCHEDULER_LISTS_FIELD)) ?: [];
        $currentSegmentsSelected = unserialize($this->getMetaValue(self::MDIRECTOR_SCHEDULER_SEGMENTS_FIELD)) ?: [];
        $currentGroupsSelected = unserialize($this->getMetaValue(self::MDIRECTOR_SCHEDULER_GROUPS_FIELD)) ?: [];
        $selected = [
            Mdirector_Newsletter_Utils::USER_LIST => $currentListsSelected,
            Mdirector_Newsletter_Utils::USER_SEGMENT => $currentSegmentsSelected,
            Mdirector_Newsletter_Utils::USER_GROUP => $currentGroupsSelected
        ];

        return $this->MDirectorUtils->getUserListsHTML($selected);
    }

    private function isSchedulerEnabled()
    {
        $status = get_post_status($this->postID);

        return $status !== self::AUTO_DRAFT_STATUS;
    }

    public function mdirectorSchedulerData($postId)
    {
        if (wp_is_post_revision($postId)) {
            return;
        }

        $this->MDirectorUtils->log(
            'Send delivery init',
            [],
            $this->MDirectorUtils::LOG_INFO
        );

        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }

        $this->setPostId($postId);

        // Verify nonce before processing any POST data.
        $nonce_value = isset( $_POST[ self::MDIRECTOR_SCHEDULER_NONCE_FIELD ] )
            ? sanitize_text_field( wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_NONCE_FIELD ] ) )
            : '';

        if ( ! wp_verify_nonce( $nonce_value, plugin_basename( __FILE__ ) ) ) {
            return;
        }

        $this->saveData();

        if ($this->isPreviewMode()) {
            $this->showPreviewMode();
        }

        if ($this->isStatusPublished() && $this->isSendMode()) {
            if (get_post_meta($this->postID, self::MDIRECTOR_ALREADY_SENT, true) === 'true') {
                $this->MDirectorUtils->log(
                    'Already sent; avoiding sending again',
                    [],
                    $this->MDirectorUtils::LOG_INFO
                );
                return;
            }

            $this->sendDelivery();
            $this->sendMode = false;
            update_post_meta($this->postID, self::MDIRECTOR_ALREADY_SENT, 'true');

            return;
        }

        $this->MDirectorUtils->bootNotices();
    }

    private function setPostId($postId)
    {
        $this->postID = $postId;

        return $this;
    }

    private function saveData() {
        // phpcs:disable WordPress.Security.NonceVerification.Missing -- nonce verified in mdirectorSchedulerData() before this method is called.
        if ( empty( $_POST ) ) {
            return false;
        }

        update_post_meta(
            $this->postID,
            self::MDIRECTOR_SCHEDULER_ACTIVE_FIELD,
            isset( $_POST[ self::MDIRECTOR_SCHEDULER_ACTIVE_FIELD ] ) ? 1 : 0
        );

        update_post_meta(
            $this->postID,
            self::MDIRECTOR_SCHEDULER_TEMPLATE_FIELD,
            isset( $_POST[ self::MDIRECTOR_SCHEDULER_TEMPLATE_FIELD ] )
                ? sanitize_text_field( wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_TEMPLATE_FIELD ] ) )
                : null
        );

        update_post_meta(
            $this->postID,
            self::MDIRECTOR_SCHEDULER_FROM_FIELD,
            isset( $_POST[ self::MDIRECTOR_SCHEDULER_FROM_FIELD ] )
                ? sanitize_text_field( wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_FROM_FIELD ] ) )
                : null
        );

        update_post_meta(
            $this->postID,
            self::MDIRECTOR_SCHEDULER_SUBJECT_FIELD,
            isset( $_POST[ self::MDIRECTOR_SCHEDULER_SUBJECT_FIELD ] )
                ? sanitize_text_field( wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_SUBJECT_FIELD ] ) )
                : null
        );

        $lists_raw = isset( $_POST[ self::MDIRECTOR_SCHEDULER_LISTS_FIELD ] )
            ? array_map( 'sanitize_text_field', (array) wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_LISTS_FIELD ] ) )
            : null;
        update_post_meta( $this->postID, self::MDIRECTOR_SCHEDULER_LISTS_FIELD, $lists_raw );

        $segments_raw = isset( $_POST[ self::MDIRECTOR_SCHEDULER_SEGMENTS_FIELD ] )
            ? array_map( 'sanitize_text_field', (array) wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_SEGMENTS_FIELD ] ) )
            : null;
        update_post_meta( $this->postID, self::MDIRECTOR_SCHEDULER_SEGMENTS_FIELD, $segments_raw );

        $groups_raw = isset( $_POST[ self::MDIRECTOR_SCHEDULER_GROUPS_FIELD ] )
            ? array_map( 'sanitize_text_field', (array) wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_GROUPS_FIELD ] ) )
            : null;
        update_post_meta( $this->postID, self::MDIRECTOR_SCHEDULER_GROUPS_FIELD, $groups_raw );

        update_post_meta(
            $this->postID,
            self::MDIRECTOR_SCHEDULER_CAMPAIGN_FIELD,
            isset( $_POST[ self::MDIRECTOR_SCHEDULER_CAMPAIGN_FIELD ] )
                ? sanitize_text_field( wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_CAMPAIGN_FIELD ] ) )
                : null
        );

        update_post_meta(
            $this->postID,
            self::MDIRECTOR_SCHEDULER_DELIVERY_FIELD,
            isset( $_POST[ self::MDIRECTOR_SCHEDULER_DELIVERY_FIELD ] )
                ? sanitize_text_field( wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_DELIVERY_FIELD ] ) )
                : null
        );
        // phpcs:enable WordPress.Security.NonceVerification.Missing
    }

    /**
     * @return bool
     */
    private function isPreviewMode() {
        // Nonce verified in mdirectorSchedulerData() before this is called.
        // phpcs:disable WordPress.Security.NonceVerification.Missing
        $save = isset( $_POST['save'] )
            ? sanitize_key( wp_unslash( $_POST['save'] ) )
            : '';
        // phpcs:enable WordPress.Security.NonceVerification.Missing
        return $save === self::MDIRECTOR_SCHEDULER_PREVIEW_FIELD;
    }

    private function showPreviewMode()
    {
        $this->deliveryPostRoutine(self::PREVIEW_MODE_ON);
        exit();
    }

    /**
     * @param $previewMode
     *
     * @return bool
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\RuntimeError
     * @throws \Twig\Error\SyntaxError
     */
    private function deliveryPostRoutine($previewMode)
    {
        $posts = $this->MDirectorUtils->getAndParseCustomPost($this->postID);
        $frequency = Mdirector_Newsletter_Utils::DAILY_FREQUENCY;
        $lang = Mdirector_Newsletter_Utils::MDIRECTOR_DEFAULT_USER_LANG;
        $isTestMode = false;
        $template = $this->getMetaValue(self::MDIRECTOR_SCHEDULER_TEMPLATE_FIELD);
        $campaign = $this->getMetaValue(self::MDIRECTOR_SCHEDULER_CAMPAIGN_FIELD);
        $lists = unserialize($this->getMetaValue(self::MDIRECTOR_SCHEDULER_LISTS_FIELD)) ?: [];
        $segments = unserialize($this->getMetaValue(self::MDIRECTOR_SCHEDULER_SEGMENTS_FIELD)) ?: [];
        $groups = unserialize($this->getMetaValue(self::MDIRECTOR_SCHEDULER_GROUPS_FIELD)) ?: [];
        $from = $this->getMetaValue(self::MDIRECTOR_SCHEDULER_FROM_FIELD);
        $subject = $this->getMetaValue(self::MDIRECTOR_SCHEDULER_SUBJECT_FIELD);
        $delivery = $this->getMetaValue(self::MDIRECTOR_SCHEDULER_DELIVERY_FIELD);

        return $this->MDirectorUtils->mdSendMail(
            $posts, $frequency, $lang, $previewMode, $isTestMode, $template,
            $campaign, $lists, $segments, $groups, $from, $subject, $delivery
        );
    }

    /**
     * @return bool
     */
    private function isStatusPublished()
    {
        return get_post_status($this->postID) === self::POST_PUBLISHED;
    }

    /**
     * @return bool
     */
    private function isSendMode() {
        // Nonce verified upstream before this is called.
        // phpcs:disable WordPress.Security.NonceVerification.Missing
        $save      = isset( $_POST['save'] ) ? sanitize_key( wp_unslash( $_POST['save'] ) ) : '';
        $send_flag = isset( $_POST[ self::MDIRECTOR_SCHEDULER_SEND_FIELD ] )
            ? sanitize_key( wp_unslash( $_POST[ self::MDIRECTOR_SCHEDULER_SEND_FIELD ] ) )
            : '';
        // phpcs:enable WordPress.Security.NonceVerification.Missing

        return ( $this->sendMode === true )
            || ( $save === self::MDIRECTOR_SCHEDULER_SEND_FIELD )
            || ( $send_flag === self::MDIRECTOR_SCHEDULER_SEND_FIELD );
    }

    private function sendDelivery()
    {
        $delivery = $this->deliveryPostRoutine(self::PREVIEW_MODE_OFF);

        if ($delivery) {
            $templateData = [
                'message' => 'SENDING-TEST__DAILY-SENDING'
            ];

            $this->MDirectorUtils->reportNotice('updatedWithDetailsInfoNotice', $templateData);
        } else {
            $templateData = [
                'message' => 'SENDING-TEST__DAILY-SENDING-ERROR',
                'details' => ': ' . __( 'NO-ENTRIES-IN-BLOG', 'emblue-newsletter' )
            ];

            $this->MDirectorUtils->reportNotice('updatedErrorNotice', $templateData);
        }
    }

    public function newPostTrigger($new_status, $old_status, $post)
    {
        if ($new_status !== self::POST_PUBLISHED || $old_status === self::POST_PUBLISHED) {
            return;
        }

        if ($post->post_type !== 'post') {
            return; // restrict the filter to a specific post type
        }

        $this->setPostId($post->ID);

        if (!$this->isSchedulerActive() || !$this->isStatusPublished()) {
            return;
        }

        $this->sendDelivery();
    }
}
