<?php

class PeepSoPostBackgrounds
{

    private static $_instance = null;
    const MODULE_ID = 111;

    public function __construct()
    {
        if (!PeepSo::get_option_new('post_backgrounds_enable', 1)) {
            return;
        }
        add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));

        // postbox
        add_filter('peepso_post_types', array($this, 'post_types'), 25, 2);
        add_filter('peepso_postbox_tabs', array($this, 'postbox_tabs'), 120);
        add_filter('peepso_postbox_interactions', array($this, 'postbox_interactions'), 110, 2);
        add_filter('peepso_postbox_types', array($this, 'filter_postbox_types'), 110, 2);

        // save additional data
        add_filter('peepso_activity_insert_data', array($this, 'activity_insert_data'));
        add_action('peepso_activity_after_add_post', array($this, 'after_add_post'));
        add_action('peepso_activity_after_save_post', array($this, 'after_add_post'), 10, 1);

        // clean post content from html tags
        add_filter('peepso_activity_post_content', array($this, 'activity_post_content'), 10, 2);

        // attach background to post
        add_action('peepso_activity_post_attachment', array($this, 'attach_background'), 10, 1);
        add_filter('peepso_activity_content', array($this, 'activity_content'), 10, 2);

        // disable repost and edit
        add_filter('peepso_post_filters', array(&$this, 'post_filters'), 10);

        // #7784 keep the local cache of default background images warm (self-heal)
        add_action(PeepSo::CRON_MAINTENANCE_EVENT, array(__CLASS__, 'ensure_local_cache'));
    }

    /**
     * Retrieve singleton class instance
     * @return PostBackgrounds instance
     */
    public static function get_instance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }
        return (self::$_instance);
    }

    /**
     * #7784 The default background images are hosted on the PeepSo CDN and cached
     * locally (wp-content/peepso/backgrounds/) on first run instead of shipping
     * ~1.4MB of PNGs inside the plugin. There are 6 bundled defaults ("1.png".."6.png").
     */
    const DEFAULT_BACKGROUNDS = 6;

    /**
     * Base URL of the default background images on the CDN (with trailing slash).
     * Override the host with the 'peepso_cdn_static_url' filter (e.g. to self-host).
     * @return string
     */
    public static function cdn_base()
    {
        $base = apply_filters('peepso_cdn_static_url', 'https://cdn.peepso.com/static');
        return trailingslashit($base) . 'backgrounds/';
    }

    /**
     * Local cache directory for the default background images (with trailing separator).
     * @return string
     */
    public static function local_dir()
    {
        return PeepSo::get_peepso_dir() . 'backgrounds' . DIRECTORY_SEPARATOR;
    }

    /**
     * Local cache URL for the default background images (with trailing slash).
     * @return string
     */
    public static function local_uri()
    {
        return PeepSo::get_peepso_uri() . 'backgrounds/';
    }

    /**
     * #7784 Resolve the URL for a bundled default background image ("1.png".."6.png").
     * Serves the locally-cached copy once downloaded, otherwise falls back to the CDN
     * so the image always renders while the cache warms.
     * @param string $filename e.g. "1.png"
     * @return string
     */
    public static function default_image_url($filename)
    {
        $filename = basename($filename);
        if (is_file(self::local_dir() . $filename)) {
            return self::local_uri() . $filename;
        }
        return self::cdn_base() . $filename;
    }

    /**
     * Legacy posts created on 9.0.4.0 and earlier (before #7784 moved the default
     * background images out of the package and onto the CDN) froze the full package URL of
     * the chosen default into 'peepso_post_background' meta
     * (.../peepso-core/assets/images/post-backgrounds/N.png). That file no longer ships, so
     * rewrite such a URL to the current resolver (local cache if warm, CDN fallback otherwise)
     * at display time. Host-agnostic (matches on the package path, not the domain), so it also
     * survives a site-domain change. Custom uploads and already-CDN/cache URLs pass through
     * untouched.
     *
     * @param string $background stored background URL from the post meta
     * @return string
     */
    public static function normalize_background_url($background)
    {
        if (is_string($background) &&
            preg_match('~/peepso-core/assets/images/post-backgrounds/([^/?#"\']+\.png)~i', $background, $m)) {
            return self::default_image_url($m[1]);
        }
        return $background;
    }

    /**
     * #7784 Download any missing default background images from the CDN into the local
     * cache (wp-content/peepso/backgrounds/). Runs on activation/upgrade and from the
     * maintenance cron as a self-heal. Throttled so an unreachable CDN is not retried
     * on every request.
     * @param bool $force skip the throttle (used on activation/upgrade)
     */
    public static function ensure_local_cache($force = false)
    {
        $dir = self::local_dir();

        $missing = array();
        for ($n = 1; $n <= self::DEFAULT_BACKGROUNDS; $n++) {
            if (!is_file($dir . $n . '.png')) {
                $missing[] = $n . '.png';
            }
        }
        if (empty($missing)) {
            return;
        }

        // Throttle repeated network attempts (e.g. CDN temporarily unreachable).
        if (!$force && get_transient('peepso_backgrounds_cache_wait')) {
            return;
        }
        set_transient('peepso_backgrounds_cache_wait', 1, HOUR_IN_SECONDS);

        if (!wp_mkdir_p($dir)) {
            return;
        }
        // Silence directory listing, matching PeepSo convention.
        if (!is_file($dir . 'index.php')) {
            @file_put_contents($dir . 'index.php', "<?php\n// Silence is golden.\n");
        }

        foreach ($missing as $filename) {
            $resp = wp_remote_get(self::cdn_base() . $filename, array('timeout' => 10));
            if (is_wp_error($resp) || 200 != wp_remote_retrieve_response_code($resp)) {
                continue;
            }
            $body = wp_remote_retrieve_body($resp);
            if ('' !== $body) {
                @file_put_contents($dir . $filename, $body);
            }
        }
    }

    /*
     * enqueue scripts for post backgrounds
     */
    public function enqueue_scripts()
    {
        wp_enqueue_script('peepso-postbox-backgrounds', PeepSo::get_asset('js/postbox/postbox-backgrounds.js'),
            array('jquery', 'jquery-ui-sortable', 'peepso', 'peepso-postbox'), PeepSo::PLUGIN_VERSION, TRUE);

        add_filter('peepso_data', function($data) {
            $data['backgrounds'] = [
                'post_max_length' => PeepSo::get_option_new('post_backgrounds_max_length')
            ];

            return $data;
        });
    }

    public function post_types($post_types, $params = array())
    {
        if ((isset($params['is_current_user']) && $params['is_current_user'] === false) || !apply_filters('peepso_permissions_post_backgrounds_create', TRUE)) {
            return ($post_types);
        }

        $post_types['post_backgrounds'] = array(
            'icon' => 'gcis gci-brush',
            'name' => __('Post background', 'peepso-core'),
            'class' => 'ps-postbox__menu-item',
        );

        return ($post_types);
    }

    public function postbox_tabs($tabs)
    {
		$PeepSoPostBackgroundsModel = new PeepSoPostBackgroundsModel(FALSE);

        $tabs['post_backgrounds'] = PeepSoTemplate::exec_template('post-backgrounds', 'postbox', [
            'post_backgrounds' => $PeepSoPostBackgroundsModel->post_backgrounds,
        ], true);

        return $tabs;
    }

    public function postbox_interactions($interactions, $params = array())
    {
        if ((isset($params['is_current_user']) && $params['is_current_user'] === false) && !apply_filters('peepso_permissions_post_backgrounds_create', TRUE)) {
            return ($interactions);
        }


        $interactions['post_backgrounds'] = array(
            'icon' => 'gcis gci-grin-hearts',
            'id' => 'post_backgrounds',
            'class' => 'ps-postbox__menu-item',
            'click' => 'return;',
            'label' => '',
            'title' => __('Post background', 'peepso-core'),
            'style' => 'display:none',
        );

        return ($interactions);
    }

    public function filter_postbox_types($types, $params = [])
    {
        if ((isset($params['is_current_user']) && $params['is_current_user'] === false) || !apply_filters('peepso_permissions_post_backgrounds_create', TRUE)) {
            return $types;
        }

        $PeepSoPostBackgroundsModel = new PeepSoPostBackgroundsModel(FALSE);
        $data = ['post_backgrounds' => $PeepSoPostBackgroundsModel->post_backgrounds];

        $types['background'] = [
            'icon' => 'pso-i-background',
            'label' => __('Background', 'peepso-core'),
            'html' => PeepSoTemplate::exec_template('post-backgrounds', 'postbox-new', $data, TRUE),
            'order' => 40,
        ];

        return $types;
    }

    /**
     * Sets the activity's module ID to the plugin's module ID
     * @param  array $activity
     * @return array
     */
    public function activity_insert_data($activity)
    {
        $input = new PeepSoInput();

        // SQL safe
        $type = $input->value('type', '', false);

        if ($type == 'post_backgrounds') {
            $activity['act_module_id'] = self::MODULE_ID;
        }

        return ($activity);
    }

    /**
     * Adds the postmeta to the post, only called when submitting from the post backgrounds tab
     * @param  int $post_id The post ID
     */
    public function after_add_post($post_id)
    {
        $act = PeepSoActivity::get_instance()->get_activity_data($post_id, self::MODULE_ID);
        if (is_object($act)) {
            $input = new PeepSoInput();
            $background = $input->value('background', null, false); // SQL safe, add_post_meta
            $text_color = $input->value('text_color', '#fff', false); // SQL safe, add_post_meta
            $preset_id = $input->value('preset_id', null, false); // SQL safe, add_post_meta

            add_post_meta($post_id, 'peepso_post_background', json_encode([
                'background' => $background,
                'text_color' => $text_color,
                'preset_id' => $preset_id
            ]));
        }
    }

    /**
     * Attach the background to the post display
     * @param  object $post The post
     */
    public function attach_background($post)
    {
        if ($post->act_module_id != self::MODULE_ID) {
            return;
        }

        $post_meta = json_decode(get_post_meta($post->ID, 'peepso_post_background', true));
        $text_color = $post_meta->text_color;
        $background = self::normalize_background_url($post_meta->background);

        $content = nl2br($post->post_content);

        $data = array(
            'id' => $post->ID,
            'text_color' => $text_color,
            'background' => $background,
            'content' => $content,
        );

        PeepSoTemplate::exec_template('post-backgrounds', 'content', $data);
    }

    public function activity_content($content, $post)
    {
        if ($post->act_module_id != self::MODULE_ID) {
            return $content;
        } else {
            return '';
        }
    }

    /**
     * Disable repost on post backgrounds
     * @param array $actions The default options per post
     * @return  array
     */
    public function post_filters($actions)
    {
        if ($actions['post']->act_module_id == self::MODULE_ID) {
            global $post;
            unset($actions['acts']['repost']);
            //unset($actions['acts']['remove_link_preview']);

            if (isset($actions['acts']['edit'])) {
                $actions['acts']['edit']['click'] = 'PsPostBackground.editPost(' . $post->ID . ', ' . $post->act_id . '); return false';
            }
        }
        return $actions;
    }

    public function activity_post_content($content, $id)
    {
        $act = PeepSoActivity::get_instance()->get_activity_data($id, self::MODULE_ID);

        if (is_object($act)) {
            $content = htmlspecialchars_decode($content);
            $content = strip_tags($content);
        };

        return $content;
    }
}
