<?php
/**
 * Cheap drift checks for the design-system index.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Index;

use LolaCoreForBricks\Support\BricksMetaKeys;

/**
 * Detects when global classes or page content changed since the last index build.
 */
class DriftDetector
{
    public function __construct(
        private readonly ?IndexState $state = null,
        private readonly ?IndexBuilder $builder = null
    ) {
    }

    public function hasClassDrift(): bool
    {
        $state = ($this->state ?? new IndexState())->get();
        $saved = $state['class_stamp'] ?? null;
        $current = $this->currentClassStamp();

        if ($saved === null || $current === null) {
            return false;
        }

        return (string) $saved !== (string) $current;
    }

    public function hasContentDrift(): bool
    {
        $state = ($this->state ?? new IndexState())->get();
        $saved = $state['max_modified'] ?? null;
        $current = $this->currentMaxModified();

        if ($saved === null || $current === null) {
            return false;
        }

        return strcmp((string) $saved, (string) $current) < 0;
    }

    /**
     * @return int[]
     */
    public function stalePostIds(): array
    {
        $state = ($this->state ?? new IndexState())->get();
        $since = $state['built_at'] ?? $state['max_modified'] ?? null;

        if ($since === null) {
            return [];
        }

        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $rows = $wpdb->get_col(
            $wpdb->prepare(
                "SELECT DISTINCT p.ID
                 FROM {$wpdb->posts} p
                 INNER JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID
                 WHERE pm.meta_key IN (%s, %s, %s)
                 AND pm.meta_value <> ''
                 AND p.post_modified_gmt > %s
                 ORDER BY p.ID ASC",
                BricksMetaKeys::PAGE_CONTENT,
                BricksMetaKeys::PAGE_HEADER,
                BricksMetaKeys::PAGE_FOOTER,
                (string) $since
            )
        );

        if (!is_array($rows)) {
            return [];
        }

        return array_values(array_map('intval', $rows));
    }

    private function currentClassStamp(): ?string
    {
        $stamp = get_option(BricksMetaKeys::OPTION_CLASS_TIMESTAMP, null);

        if ($stamp === null || $stamp === false || $stamp === '') {
            return null;
        }

        return is_scalar($stamp) ? (string) $stamp : wp_json_encode($stamp);
    }

    private function currentMaxModified(): ?string
    {
        return $this->queryMaxModified();
    }

    private function queryMaxModified(): ?string
    {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $max = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT MAX(p.post_modified_gmt)
                 FROM {$wpdb->posts} p
                 INNER JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID
                 WHERE pm.meta_key IN (%s, %s, %s)
                 AND pm.meta_value <> ''",
                BricksMetaKeys::PAGE_CONTENT,
                BricksMetaKeys::PAGE_HEADER,
                BricksMetaKeys::PAGE_FOOTER
            )
        );

        return is_string($max) && $max !== '' ? $max : null;
    }
}
