<?php

/**
 * LolaCore — Hub Memory Transparency
 *
 * @package LolaCore
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\Hub;

use LolaCore\Memory\MemoryManager;

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared -- Custom LolaCore table queries with validated inputs.

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Surfaces fleet memory reconcile metadata on the child (C2) and supports "forget operator facts".
 */
final class HubMemoryTransparency
{
    public const CONFIG_KEY = 'hub_last_memory_reconcile';

    /**
     * @return array{synced_at: string, fact_count: int, master_label: string}|null
     */
    public function getLastReconcile(): ?array
    {
        $raw = $this->getConfigValue(self::CONFIG_KEY, '');

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

        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return null;
        }

        $syncedAt = (string) ($decoded['synced_at'] ?? '');
        if ($syncedAt === '') {
            return null;
        }

        return [
            'synced_at'     => $syncedAt,
            'fact_count'    => (int) ($decoded['fact_count'] ?? 0),
            'master_label'  => (string) ($decoded['master_label'] ?? ''),
        ];
    }

    /**
     * Called by C4 when a reconcile batch completes.
     *
     * @param array{synced_at?: string, fact_count?: int, master_label?: string} $payload
     */
    public function recordReconcile(array $payload): void
    {
        $this->setConfigValue(self::CONFIG_KEY, wp_json_encode([
            'synced_at'    => (string) ($payload['synced_at'] ?? current_time('mysql')),
            'fact_count'   => (int) ($payload['fact_count'] ?? 0),
            'master_label' => (string) ($payload['master_label'] ?? ''),
        ]) ?: '{}');
    }

    /**
     * Purges memory facts written by the fleet operator (source = hub). Local owner facts stay intact.
     *
     * @return int Number of rows deleted.
     */
    public function forgetOperatorFacts(): int
    {
        global $wpdb;
        $table = $wpdb->prefix . 'lolacore_memory';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return (int) $wpdb->query(
            $wpdb->prepare("DELETE FROM {$table} WHERE source = %s", 'hub')
        );
    }

    public function clearReconcileMetadata(): void
    {
        $this->deleteConfigValue(self::CONFIG_KEY);
    }

    private function getConfigValue(string $key, ?string $default = null): ?string
    {
        global $wpdb;
        $table = $wpdb->prefix . 'lolacore_config';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $value = $wpdb->get_var(
            $wpdb->prepare("SELECT config_value FROM {$table} WHERE config_key = %s", $key)
        );

        return $value ?? $default;
    }

    private function setConfigValue(string $key, string $value): void
    {
        global $wpdb;
        $table = $wpdb->prefix . 'lolacore_config';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->query(
            $wpdb->prepare(
                "INSERT INTO {$table} (config_key, config_value) VALUES (%s, %s)
                 ON DUPLICATE KEY UPDATE config_value = VALUES(config_value)",
                $key,
                $value,
            )
        );
    }

    private function deleteConfigValue(string $key): void
    {
        global $wpdb;
        $table = $wpdb->prefix . 'lolacore_config';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->delete($table, ['config_key' => $key], ['%s']);
    }
}
