<?php

namespace Blazemedia\Affiliation\Providers;

use Blazemedia\Affiliation\Utils\Logger;
use Blazemedia\Affiliation\Rendering\RenderResponse;
use Blazemedia\Affiliation\Support\Environment;
use Blazemedia\Affiliation\Rendering\PurgeClient;

class CronServiceProvider implements Contract\ServiceProviderInterface
{
    use Trait\HasServerRequest;
    use Trait\HasPostMetaManager;
    use Trait\HandleZoneFormat;
    use Trait\LinkConverter;

    private PurgeClient $purgeClient;
    const CRON_HOOK = 'blz_affiliation_cron_update_formats';
    const OFFSET_OPTION = 'blz_affiliation_cron_offset';

    public function __construct()
    {
        add_filter('cron_schedules', [ $this, 'registerFourHourSchedule' ]);
        add_action('init', [ $this, 'register' ]);
        add_action(self::CRON_HOOK, [ $this, 'runBatch' ]);

        $this->purgeClient = new PurgeClient();
    }

    public function register(): void
    {
        // Ensure the hook uses the 4-hour schedule
        $current = wp_get_schedule(self::CRON_HOOK);
        if ($current && $current !== 'every_four_hours') {
            wp_clear_scheduled_hook(self::CRON_HOOK);
        }
        if (!wp_next_scheduled(self::CRON_HOOK)) {
            wp_schedule_event(time() + 60, 'every_four_hours', self::CRON_HOOK);
        }
    }

    /**
     * Adds a 4-hour schedule interval.
     */
    public function registerFourHourSchedule(array $schedules): array
    {
        if (!isset($schedules['every_four_hours'])) {
            $schedules['every_four_hours'] = [
                'interval' => 4 * HOUR_IN_SECONDS,
                'display'  => __('Every 4 Hours', 'blz-affiliation'),
            ];
        }
        return $schedules;
    }

    /**
     * Processes 10 posts per run: clears stored formats and re-renders them.
     */
    public function runBatch(): void
    {
        try {
            $postTypes = Environment::get('BLAZE_AFFILIATION_POST_TYPES');
            if (!is_array($postTypes) || empty($postTypes)) return;

            $offset = (int) get_option(self::OFFSET_OPTION, 0);
            global $wpdb;
            $metaTable  = $wpdb->postmeta;

            // Solo postmeta: estraiamo post_id che hanno i meta dei formati
            $sql = "
                SELECT DISTINCT m.post_id
                FROM {$metaTable} m
                WHERE m.meta_key IN ('_blz_affiliation_formats', '_blz_affiliation_formats_hook', '_blz_affiliation_formats_child')
                ORDER BY m.post_id DESC
                LIMIT %d OFFSET %d
            ";
            $prepared = $wpdb->prepare($sql, [10, $offset]);
            $ids = array_map('intval', (array) $wpdb->get_col($prepared));
            if (empty($ids)) {
                // Reset offset and exit; next run will start from the beginning
                update_option(self::OFFSET_OPTION, 0, false);
                return;
            }

            foreach ($ids as $postId) {
                $post = get_post($postId);
                if (!$post instanceof \WP_Post) continue;
                // Filtro rapido lato PHP per status/type per evitare join
                if ($post->post_status !== 'publish') continue;
                if (!in_array($post->post_type, $postTypes, true)) continue;

                // Prepare content similarly to other flows
                $working = clone $post;
                $working = $this->handleOldShortcode($working);
                $working = $this->handleZoneRendering($working);

                // Request fresh formats and persist
                $this->purgeFormat($working);

                $renderResponse = $this->requestFormats($working);
                if ($renderResponse->isEmpty()) {
                    Logger::write("CronServiceProvider: empty render response for post {$post->ID}", 'ERROR');
                    continue;
                }
                $this->setMetaRenderResponse($post, $renderResponse);
            }

            // Advance offset; if fewer than 10 processed, wrap to 0
            $newOffset = (count($ids) < 10) ? 0 : ($offset + 10);
            update_option(self::OFFSET_OPTION, $newOffset, false);
        } catch (\Throwable $e) {
            Logger::write('CronServiceProvider failed: ' . $e->getMessage(), 'ERROR');
        }
    }

    private function purgeFormat(\WP_Post $post): void
    {
        $formatsMetaValue = get_post_meta($post->ID, '_blz_affiliation_formats', true);
        $signature = get_post_meta($post->ID, '_blz_affiliation_formats_signature', true);
        if (empty($formatsMetaValue)) return;

        $formatsUnserialized = unserialize($formatsMetaValue);

        if (empty($formatsUnserialized['replacements'])) return;

        foreach ($formatsUnserialized['replacements'] as $format) {
            $this->purgeClient->purgeShortcode($format['html'], $signature);
        }
    }
}


