<?php
/**
 * Cache data.
 */

namespace Extendify\Shared\DataProvider;

defined('ABSPATH') || die('No direct access.');

use Extendify\Assist\Controllers\DomainsSuggestionController;
use Extendify\Assist\Controllers\RecommendationsController;
use Extendify\HelpCenter\Controllers\SupportArticlesController;
use Extendify\Shared\Services\Sanitizer;

/**
 * The cache data class.
 */
class ResourceData
{
    /**
     * Initiate the class.
     *
     * @return void
     */
    public function __construct()
    {
        if (!(is_admin() || defined('DOING_CRON'))) {
            return;
        }

        // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
        add_action('http_api_curl', function ($handle, $_req, $url) {
            // Allow a longer timeout for this request since it happens in a scheduler.
            if (strpos($url, 'api/domains/suggest') !== false) {
                curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 150); // phpcs:ignore
                curl_setopt($handle, CURLOPT_TIMEOUT, 150); // phpcs:ignore
            }
        }, 100, 3);
    }

    /**
     * Register the cache schedule.
     *
     * @return void
     */
    public static function scheduleCache()
    {
        // phpcs:ignore WordPress.WP.CronInterval -- Verified > 30 days.
        \add_filter('cron_schedules', function ($schedules) {
            $schedules['every_month'] = [
                'interval' => (30 * DAY_IN_SECONDS), // phpcs:ignore
                'display' => __('Every month', 'extendify-local'),
            ];
            return $schedules;
        });

        if (! \wp_next_scheduled('extendify_cache_data')) {
            \wp_schedule_event(
                (\current_time('timestamp') + DAY_IN_SECONDS), // phpcs:ignore
                'every_month',
                'extendify_cache_data'
            );
        }

        \add_action('extendify_cache_data', function () {
            if (!defined('EXTENDIFY_PARTNER_ID')) {
                return;
            }

            $resourceData = new ResourceData();
            $resourceData->cacheData('recommendations', RecommendationsController::fetchRecommendations()->get_data());
            $resourceData->cacheData('supportArticles', SupportArticlesController::fetchArticles()->get_data());
        });

        // For domains, only update when the site title changes.
        \add_action('update_option_blogname', function () {
            if (!defined('EXTENDIFY_PARTNER_ID')) {
                return;
            }

            wp_schedule_single_event(time(), 'update_domains_cache');
            spawn_cron();
        });

        \add_action('update_domains_cache', function () {
            if (!defined('EXTENDIFY_PARTNER_ID')) {
                return;
            }

            $data = DomainsSuggestionController::fetchDomainSuggestions()->get_data();
            set_transient('extendify_domains', Sanitizer::sanitizeArray($data));
        });

    }

    /**
     * Return the data.
     *
     * @return array
     */
    public function getData()
    {
        $domains = get_transient('extendify_domains');
        if ($domains === false) {
            // TODO: Should we spawn a cron here to refetch the data?
            $domains = [];
        }

        return [
            'recommendations' => $this->recommendations(),
            'supportArticles' => $this->supportArticles(),
            // Domains are now cached forever until the site title changes.
            'domains' => $domains,
        ];
    }

    /**
     * Return the recommendations. Fetch them if not found (or on a schedule).
     *
     * @return mixed|\WP_REST_Response
     */
    protected function recommendations()
    {
        $recommendations = get_transient('extendify_recommendations');
        if ($recommendations === false) {
            // Fetch these immediately if not found.
            $recommendations = RecommendationsController::fetchRecommendations()->get_data();
            $this->cacheData('recommendations', $recommendations);
        }

        return $recommendations;
    }

    /**
     * Return the support articles. Fetch them if not found (or on a schedule).
     *
     * @return mixed|\WP_REST_Response
     */
    protected function supportArticles()
    {
        $supportArticles = get_transient('extendify_supportArticles');
        if ($supportArticles === false) {
            $supportArticles = SupportArticlesController::fetchArticles()->get_data();
            $this->cacheData('supportArticles', $supportArticles);
        }

        return $supportArticles;
    }

    /**
     * This stores the data as a transient.
     *
     * @param string $functionName The function name that we use in the store.
     * @param array  $data         The extracted data returned from the HTTP request.
     * @return void
     */
    protected function cacheData($functionName, $data)
    {
        // The scheduler runs monthly, one day before the cache expires.
        set_transient('extendify_' . $functionName, Sanitizer::sanitizeArray($data), (DAY_IN_SECONDS + MONTH_IN_SECONDS));
    }
}
