<?php
/**
 * Keeps the design index aligned with Bricks saves.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Index;

use LolaCoreForBricks\Support\BricksMetaKeys;

/**
 * Hooks-driven invalidation and targeted reindexing.
 */
class IndexInvalidator
{
    public const CRON_HOOK = 'lolacore_bricks_reindex_post';

    public function register(): void
    {
        add_action('updated_post_meta', [$this, 'onUpdatedPostMeta'], 10, 4);
        add_action('deleted_post', [$this, 'onDeletedPost'], 10, 1);
        add_action(self::CRON_HOOK, [$this, 'onScheduledPostReindex'], 10, 1);

        foreach (BricksMetaKeys::globalOptionHooks() as $optionName) {
            add_action('update_option_' . $optionName, [$this, 'onGlobalOptionUpdated'], 10, 2);
        }
    }

    public function onUpdatedPostMeta(int $metaId, int $postId, string $metaKey, mixed $metaValue): void
    {
        unset($metaId, $metaValue);

        if (!in_array($metaKey, BricksMetaKeys::pageMetaKeys(), true)
            && $metaKey !== BricksMetaKeys::PAGE_SETTINGS) {
            return;
        }

        $builder = new IndexBuilder();
        if ($builder->shouldDeferPostIndexing($postId)) {
            wp_schedule_single_event(time() + 1, self::CRON_HOOK, [$postId]);

            return;
        }

        $builder->indexPost($postId);
        $this->touchPartialBuildState();
    }

  /**
     * @param mixed $oldValue
     * @param mixed $value
     */
    public function onGlobalOptionUpdated(mixed $oldValue, mixed $value): void
    {
        unset($oldValue, $value);

        $builder = new IndexBuilder();
        $builder->indexGlobalScopes();

        $stateStore = new IndexState();
        $state      = $stateStore->get();
        $state['class_stamp'] = get_option(BricksMetaKeys::OPTION_CLASS_TIMESTAMP, null);
        $stateStore->save($state);
    }

    public function onDeletedPost(int $postId): void
    {
        (new IndexRepository())->deleteForPost($postId);
    }

    public function onScheduledPostReindex(int $postId): void
    {
        if ($postId <= 0) {
            return;
        }

        (new IndexBuilder())->indexPost($postId);
        $this->touchPartialBuildState();
    }

    private function touchPartialBuildState(): void
    {
        $stateStore = new IndexState();
        $state      = $stateStore->get();

        if (($state['finished'] ?? false) === true) {
            $state['max_modified'] = (new IndexBuilder())->discoverPostIds() === []
                ? $state['max_modified']
                : current_time('mysql', true);
            $stateStore->save($state);
        }
    }
}
