<?php

/**
 * @package     PublishPress\ChecklistsPro
 * @author      PublishPress <help@publishpress.com>
 * @copyright   copyright (C) 2019 PublishPress. All rights reserved.
 * @license     GPLv2 or later
 * @since       1.0.0
 */

namespace PublishPress\ChecklistsPro\ProhibitedWords\Requirement;

use PublishPress\Checklists\Core\Requirement\Base_multiple;

defined('ABSPATH') or die('No direct script access allowed.');

class ProhibitedWords extends Base_multiple
{
    /**
     * @var string
     */
    public $name = 'prohibited_words';

    /**
     * @var string
     */
    public $group = 'content';

    /**
     * @var int
     */
    public $position = 119;

    public function init_language()
    {
        $this->lang['label'] = __('Prohibited words: %s', 'publishpress-checklists-pro');
        $this->lang['label_settings'] = __('Prohibited words', 'publishpress-checklists-pro');
        $this->lang['label_option_description'] = __(
            'Enter prohibited words or phrases separated by commas. Matching is case-insensitive and ignores HTML tags.',
            'publishpress-checklists-pro'
        );
    }

    public function get_current_status($post, $option_value)
    {
        if (empty($option_value)) {
            return true;
        }

        $content = (property_exists($post, 'post_content') && is_string($post->post_content)) ? $post->post_content : '';

        return empty($this->get_matched_words($content, $option_value));
    }

    public function filter_requirements_list($requirements, $post)
    {
        if ($post->post_type !== $this->post_type) {
            return $requirements;
        }

        $requirements = parent::filter_requirements_list($requirements, $post);

        if (!isset($requirements[$this->name])) {
            return $requirements;
        }

        $option_name_multiple = $this->name . '_' . $this->field_name;
        $option_value = [];
        if (isset($this->module->options->{$option_name_multiple}[$this->post_type])) {
            $option_value = $this->module->options->{$option_name_multiple}[$this->post_type];
        }

        if (!empty($option_value)) {
            $formatted_words = implode(', ', $option_value);

            if ('' !== trim($this->get_editor_label())) {
                $requirements[$this->name]['label'] = sprintf(
                    __('%1$s - %2$s', 'publishpress-checklists-pro'),
                    trim($this->get_editor_label()),
                    $formatted_words
                );
            } else {
                $requirements[$this->name]['label'] = sprintf($this->lang['label'], $formatted_words);
            }
        } elseif ('' !== trim($this->get_editor_label())) {
            $requirements[$this->name]['label'] = trim($this->get_editor_label());
        }

        return $requirements;
    }

    public function get_setting_field_html($css_class = '')
    {
        $html = '';

        $post_type = esc_attr($this->post_type);
        $option_name_multiple = $this->name . '_' . $this->field_name;
        $option_value = [];

        if (isset($this->module->options->{$option_name_multiple}[$post_type])) {
            $option_value = $this->module->options->{$option_name_multiple}[$post_type];
        }

        $name = "{$this->module->options_group_name}[{$option_name_multiple}][{$post_type}]";
        $id = "{$post_type}-{$this->module->slug}-{$option_name_multiple}";
        $words = implode(', ', $option_value);

        $html .= sprintf(
            '<textarea id="%s" name="%s" rows="5" class="large-text code pp-checklists-full-width">%s</textarea>',
            esc_attr($id),
            esc_attr($name),
            esc_textarea($words)
        );

        if (isset($this->lang['label_option_description'])) {
            $html .= '<p class="pp-checklists-editable-by-description">' . esc_html($this->lang['label_option_description']) . '</p>';
        }

        return $html;
    }

    protected function get_setting_drop_down_labels()
    {
        return [];
    }

    public function filter_settings_validate($new_options)
    {
        if (isset($new_options[$this->name][$this->post_type])) {
            if (static::VALUE_YES !== $new_options[$this->name][$this->post_type]) {
                $new_options[$this->name][$this->post_type] = static::VALUE_NO;
            }
        } else {
            $new_options[$this->name][$this->post_type] = static::VALUE_NO;
        }

        $custom_label_key = $this->name . '_custom_label';
        if (isset($new_options[$custom_label_key][$this->post_type])) {
            $new_options[$custom_label_key][$this->post_type] = sanitize_text_field(
                $new_options[$custom_label_key][$this->post_type]
            );
        }

        $editor_label_key = $this->name . '_editor_label';
        if (isset($new_options[$editor_label_key][$this->post_type])) {
            $new_options[$editor_label_key][$this->post_type] = sanitize_text_field(
                $new_options[$editor_label_key][$this->post_type]
            );
        }

        $option_name_multiple = $this->name . '_' . $this->field_name;
        $raw_value = '';

        if (isset($new_options[$option_name_multiple][$this->post_type])) {
            $raw_value = $new_options[$option_name_multiple][$this->post_type];
        }

        if (is_array($raw_value)) {
            $raw_value = implode(', ', $raw_value);
        }

        $lines = explode(',', (string) $raw_value);
        $words = [];

        foreach ($lines as $line) {
            $word = sanitize_text_field(wp_unslash($line));
            $word = trim($word);

            if ('' === $word) {
                continue;
            }

            if (!in_array($word, $words, true)) {
                $words[] = $word;
            }
        }

        $new_options[$option_name_multiple][$this->post_type] = $words;

        return $new_options;
    }

    private function get_matched_words($content, array $words)
    {
        $text_content = wp_strip_all_tags((string) $content);
        $matches = [];

        foreach ($words as $word) {
            if ($this->contains_word($text_content, $word)) {
                $matches[] = $word;
            }
        }

        return $matches;
    }

    private function contains_word($content, $word)
    {
        $word = trim((string) $word);
        if ('' === $word) {
            return false;
        }

        $pattern = $this->build_word_pattern($word);

        return 1 === preg_match($pattern, $content);
    }

    private function build_word_pattern($word)
    {
        $escaped_word = preg_quote($word, '/');
        $prefix = preg_match('/^[[:alnum:]_]/u', $word) ? '(?<![[:alnum:]_])' : '';
        $suffix = preg_match('/[[:alnum:]_]$/u', $word) ? '(?![[:alnum:]_])' : '';

        return '/' . $prefix . $escaped_word . $suffix . '/iu';
    }
}
