<?php
declare(strict_types=1);

namespace ProRank\SEO\Modules\Content;

use ProRank\SEO\Modules\BaseModule;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

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

/**
 * RSS content controls.
 */
class RSSContentModule extends BaseModule {

    private const OPTION = 'prorank_rss_content_settings';

    public function __construct() {
        $this->slug = 'rss_content';
        $this->name = 'RSS Content';
        $this->description = 'Customize RSS feed before/after content and attribution.';
        $this->parent_slug = 'content';
    }

    public function init_hooks(): void {
        add_action('rest_api_init', [$this, 'register_rest_routes']);

        $settings = $this->get_settings();
        if (empty($settings['enabled'])) {
            return;
        }

        add_filter('the_excerpt_rss', [$this, 'filter_feed_excerpt'], 20);
        add_filter('the_content_feed', [$this, 'filter_feed_content'], 20, 2);
        add_action('rss2_ns', [$this, 'output_rss_namespace']);
        add_action('rss2_item', [$this, 'output_rss_item_meta'], 20);
    }

    public function register_rest_routes(): void {
        register_rest_route('prorank-seo/v1', '/rss-content/settings', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'get_settings_response'],
                'permission_callback' => [$this, 'can_manage_options'],
            ],
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'update_settings_response'],
                'permission_callback' => [$this, 'can_manage_options'],
            ],
        ]);
    }

    public function can_manage_options(): bool {
        return current_user_can('manage_options');
    }

    public function get_settings_response(): WP_REST_Response {
        return new WP_REST_Response([
            'success' => true,
            'data' => $this->get_settings(),
        ]);
    }

    public function update_settings_response(WP_REST_Request $request): WP_REST_Response {
        $current = $this->get_settings();
        $settings = [
            'enabled' => $request->has_param('enabled') ? (bool) $request->get_param('enabled') : (bool) $current['enabled'],
            'prepend_content' => $request->has_param('prepend_content') ? wp_kses_post((string) $request->get_param('prepend_content')) : (string) $current['prepend_content'],
            'append_content' => $request->has_param('append_content') ? wp_kses_post((string) $request->get_param('append_content')) : (string) $current['append_content'],
            'append_attribution' => $request->has_param('append_attribution') ? (bool) $request->get_param('append_attribution') : (bool) $current['append_attribution'],
            'append_canonical' => $request->has_param('append_canonical') ? (bool) $request->get_param('append_canonical') : (bool) $current['append_canonical'],
        ];

        update_option(self::OPTION, $settings, false);

        return new WP_REST_Response([
            'success' => true,
            'data' => $settings,
        ]);
    }

    public function filter_feed_excerpt(string $content): string {
        return $this->decorate_feed_content($content);
    }

    public function filter_feed_content(string $content, string $feed_type = 'rss2'): string {
        return $this->decorate_feed_content($content);
    }

    public function output_rss_item_meta(): void {
        $settings = $this->get_settings();
        if (empty($settings['enabled']) || empty($settings['append_canonical'])) {
            return;
        }

        $canonical = $this->get_current_canonical();
        if ($canonical === '') {
            return;
        }

        echo "\n\t" . '<prorank:canonical>' . esc_url($canonical) . '</prorank:canonical>' . "\n";
    }

    public function output_rss_namespace(): void {
        echo ' xmlns:prorank="https://prorank.io/rss/1.0"';
    }

    private function decorate_feed_content(string $content): string {
        $settings = $this->get_settings();
        if (empty($settings['enabled'])) {
            return $content;
        }

        $prepend = $this->replace_tokens((string) $settings['prepend_content']);
        $append = $this->replace_tokens((string) $settings['append_content']);

        if (!empty($settings['append_attribution'])) {
            $append .= "\n\n" . sprintf(
                '<p>%s <a href="%s">%s</a>.</p>',
                esc_html__('Originally published on', 'prorank-seo'),
                esc_url(home_url('/')),
                esc_html(get_bloginfo('name'))
            );
        }

        return trim($prepend . "\n\n" . $content . "\n\n" . $append);
    }

    private function replace_tokens(string $content): string {
        if ($content === '') {
            return '';
        }

        $post_id = get_the_ID();
        $canonical = $this->get_current_canonical();
        $author_name = '';
        if ($post_id) {
            $author_id = (int) get_post_field('post_author', $post_id);
            $author_name = $author_id > 0 ? (string) get_the_author_meta('display_name', $author_id) : '';
        }

        $replacements = [
            '%site_name%' => get_bloginfo('name'),
            '%site_url%' => home_url('/'),
            '%post_title%' => $post_id ? get_the_title($post_id) : '',
            '%post_url%' => $post_id ? get_permalink($post_id) : '',
            '%author_name%' => $author_name,
            '%canonical_url%' => $canonical,
        ];

        return strtr($content, $replacements);
    }

    private function get_current_canonical(): string {
        $post_id = get_the_ID();
        if (!$post_id) {
            return '';
        }

        $custom = (string) get_post_meta($post_id, '_prorank_seo_canonical_url', true);
        if ($custom !== '') {
            return $custom;
        }

        $permalink = get_permalink($post_id);
        return is_string($permalink) ? $permalink : '';
    }

    private function get_settings(): array {
        $settings = get_option(self::OPTION, []);
        if (!is_array($settings)) {
            $settings = [];
        }

        return wp_parse_args($settings, [
            'enabled' => false,
            'prepend_content' => '',
            'append_content' => '',
            'append_attribution' => true,
            'append_canonical' => true,
        ]);
    }
}
