<?php

declare(strict_types=1);

namespace FleekDash\Admin\Menu;

/**
 * Admin menu snapshot persistence in WordPress user_meta.
 * Extracted from MenuCaptureService to keep that class under Sonar method limits.
 *
 * @package FleekDash\Admin\Menu
 */
final class MenuSnapshotUserMeta
{
    public const META_SNAPSHOT = '_fleekdash_admin_menu_snapshot_v1';
    public const META_HASH = '_fleekdash_admin_menu_snapshot_hash_v1';
    public const META_UPDATED_AT = '_fleekdash_admin_menu_snapshot_updated_at_v1';

    public static function getUpdatedAt(int $user_id): int
    {
        if ($user_id <= 0) {
            return 0;
        }

        return (int) \get_user_meta($user_id, self::META_UPDATED_AT, true);
    }

    /** Soft-delete: mark snapshot stale (fallback still allowed in REST). */
    public static function markUserStale(int $user_id): void
    {
        if ($user_id <= 0) {
            return;
        }

        \update_user_meta($user_id, self::META_UPDATED_AT, -1);
    }

    public static function hardDeleteUser(int $user_id): void
    {
        if ($user_id <= 0) {
            return;
        }

        \delete_user_meta($user_id, self::META_SNAPSHOT);
        \delete_user_meta($user_id, self::META_HASH);
        \delete_user_meta($user_id, self::META_UPDATED_AT);
    }

    public static function markAllStale(): void
    {
        global $wpdb;
        $metaKey = self::META_UPDATED_AT;
        // Process in batches to avoid long-running table locks on large sites.
        $batchLimit = 1000;
        $affected = $batchLimit;
        while ($affected === $batchLimit) {
            $affected = $wpdb->query($wpdb->prepare(
                "UPDATE {$wpdb->usermeta} SET meta_value = %s WHERE meta_key = %s AND meta_value <> %s LIMIT %d",
                '-1',
                $metaKey,
                '-1',
                $batchLimit,
            ));
        }
    }

    public static function hardDeleteAll(): void
    {
        \delete_metadata('user', 0, self::META_SNAPSHOT, '', true);
        \delete_metadata('user', 0, self::META_HASH, '', true);
        \delete_metadata('user', 0, self::META_UPDATED_AT, '', true);
    }

    /**
     * @param array<int|string, mixed> $menu
     * @param array<int|string, mixed> $submenu
     */
    public static function persistIfChanged(int $user_id, array $menu, array $submenu): void
    {
        if ($user_id <= 0) {
            return;
        }

        if (empty($menu) || !\is_array($menu)) {
            return;
        }

        $snapshot = [
            'menu' => $menu,
            'submenu' => $submenu,
        ];

        $snapshot_hash = \md5(\wp_json_encode($snapshot));
        $previous_hash = \get_user_meta($user_id, self::META_HASH, true);

        if (\is_string($previous_hash) && $previous_hash === $snapshot_hash) {
            return;
        }

        \update_user_meta($user_id, self::META_SNAPSHOT, $snapshot);
        \update_user_meta($user_id, self::META_HASH, $snapshot_hash);
        \update_user_meta($user_id, self::META_UPDATED_AT, \time());
    }

    /**
     * @return array{menu: array, submenu: array, is_stale: bool}|null
     */
    public static function readForRestoration(int $user_id, bool $allowStale): ?array
    {
        $snapshot = \get_user_meta($user_id, self::META_SNAPSHOT, true);
        $updated_at = (int) \get_user_meta($user_id, self::META_UPDATED_AT, true);
        $isStale = $updated_at === -1;

        $loaded = !empty($snapshot) && \is_array($snapshot) && (!$isStale || $allowStale);
        if (!$loaded) {
            return null;
        }

        $menu = $snapshot['menu'] ?? null;
        $submenu = $snapshot['submenu'] ?? null;
        if (empty($menu) || !\is_array($menu)) {
            return null;
        }

        return [
            'menu' => $menu,
            'submenu' => \is_array($submenu) ? $submenu : [],
            'is_stale' => $isStale,
        ];
    }
}
