<?php

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Keeps the opaque AI Visibility proposal correlation bounded while an
 * approved proposal travels through an existing canonical apply lane.
 *
 * This class does not call the API and cannot apply or record an
 * intervention. The API revalidates the exact bundle, plan and proposal
 * before accepting a verified readback.
 */
final class Aysa_AI_Visibility_Intervention_Correlation {
    public static function normalize($value) {
        if (!is_array($value)) {
            return array();
        }

        $plan_hash = strtolower(sanitize_text_field((string) ($value['bundle_plan_hash'] ?? '')));
        $normalized = array(
            'contract_version' => absint($value['contract_version'] ?? 0),
            'bundle_id' => absint($value['bundle_id'] ?? 0),
            'bundle_plan_hash' => $plan_hash,
            'insight_id' => absint($value['insight_id'] ?? 0),
            'canonical_lane' => sanitize_key((string) ($value['canonical_lane'] ?? '')),
            'canonical_action_key' => sanitize_key((string) ($value['canonical_action_key'] ?? '')),
            'canonical_proposal_id' => sanitize_text_field((string) ($value['canonical_proposal_id'] ?? '')),
            'requires_verified_apply_readback' => !empty($value['requires_verified_apply_readback']),
            'direct_callback_from_browser_allowed' => !empty($value['direct_callback_from_browser_allowed']),
        );

        if ($normalized['contract_version'] !== 1
            || $normalized['bundle_id'] <= 0
            || preg_match('/^[a-f0-9]{64}$/', $normalized['bundle_plan_hash']) !== 1
            || $normalized['insight_id'] <= 0
            || $normalized['canonical_lane'] === ''
            || $normalized['canonical_action_key'] === ''
            || $normalized['canonical_proposal_id'] === ''
            || !$normalized['requires_verified_apply_readback']
            || $normalized['direct_callback_from_browser_allowed']) {
            return array();
        }

        if (isset($value['expected_impact']) && is_array($value['expected_impact'])) {
            $normalized['expected_impact'] = self::sanitize_map($value['expected_impact']);
        }
        return $normalized;
    }

    private static function sanitize_map($value, $depth = 0) {
        if (!is_array($value) || $depth >= 3) {
            return array();
        }
        $result = array();
        foreach (array_slice($value, 0, 25, true) as $key => $item) {
            $safe_key = sanitize_key((string) $key);
            if ($safe_key === '') {
                continue;
            }
            if (is_array($item)) {
                $result[$safe_key] = self::sanitize_map($item, $depth + 1);
            } elseif (is_bool($item) || is_int($item) || is_float($item)) {
                $result[$safe_key] = $item;
            } elseif (is_scalar($item)) {
                $result[$safe_key] = sanitize_text_field((string) $item);
            }
        }
        return $result;
    }
}
