<?php
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Privacy-first sanitizer for every AI payload sent by AI Flash Tune.
 *
 * The goal is to keep AI requests useful while avoiding personal/customer data.
 * It removes known PII keys, redacts common PII patterns inside strings, and
 * limits oversized fields so external AI calls stay predictable.
 */
class AIFLT_AI_Payload_Sanitizer {

    private static $removed_count = 0;
    private static $redacted_count = 0;

    public static function sanitize($payload, string $privacy = 'aggregate_only') {
        self::$removed_count = 0;
        self::$redacted_count = 0;
        return self::sanitize_value($payload, sanitize_key($privacy), 0);
    }

    public static function get_last_stats(): array {
        return [
            'removed_fields' => self::$removed_count,
            'redacted_values' => self::$redacted_count,
        ];
    }

    public static function hash_payload($payload): string {
        return hash('sha256', wp_json_encode($payload));
    }

    private static function sanitize_value($value, string $privacy, int $depth) {
        if ($depth > 12) {
            self::$removed_count++;
            return '[removed:depth-limit]';
        }

        if (is_array($value)) {
            $clean = [];
            foreach ($value as $key => $child) {
                $key_string = is_string($key) ? $key : (string) $key;
                if (self::is_blocked_key($key_string, $privacy)) {
                    self::$removed_count++;
                    continue;
                }
                $clean[$key] = self::sanitize_value($child, $privacy, $depth + 1);
            }
            return $clean;
        }

        if (is_string($value)) {
            return self::sanitize_string($value);
        }

        if (is_numeric($value) || is_bool($value) || is_null($value)) {
            return $value;
        }

        return self::sanitize_string(wp_json_encode($value));
    }

    private static function is_blocked_key(string $key, string $privacy): bool {
        $normalized = strtolower(trim($key));
        $normalized = str_replace(['-', ' '], '_', $normalized);

        $blocked_exact = [
            'email', 'customer_email', 'billing_email', 'shipping_email', 'guest_email',
            'phone', 'telephone', 'billing_phone', 'shipping_phone',
            'address', 'address_1', 'address_2', 'billing_address_1', 'billing_address_2', 'shipping_address_1', 'shipping_address_2',
            'city', 'postcode', 'zip', 'zipcode', 'billing_postcode', 'shipping_postcode',
            'first_name', 'last_name', 'full_name', 'customer_name', 'name', 'display_name', 'user_login', 'username',
            'ip', 'ip_address', 'user_ip', 'remote_addr',
            'password', 'pass', 'token', 'secret', 'api_key', 'apikey', 'authorization', 'auth', 'cookie', 'session_token',
            'order_note', 'customer_note', 'private_note',
        ];

        if (in_array($normalized, $blocked_exact, true)) {
            return true;
        }

        $blocked_contains = ['email', 'phone', 'address', 'postcode', 'password', 'secret', 'token', 'cookie', 'ip_address'];
        foreach ($blocked_contains as $needle) {
            if (strpos($normalized, $needle) !== false) {
                return true;
            }
        }

        // Aggregate-only mode is stricter: do not send user/order identifiers.
        if ($privacy === 'aggregate_only') {
            foreach (['user_id', 'customer_id', 'order_id', 'session_id', 'visit_id'] as $identifier) {
                if ($normalized === $identifier || strpos($normalized, $identifier) !== false) {
                    return true;
                }
            }
        }

        return false;
    }

    private static function sanitize_string(string $value): string {
        $original = $value;
        $value = wp_strip_all_tags($value);
        $value = html_entity_decode($value, ENT_QUOTES, get_bloginfo('charset') ?: 'UTF-8');

        // Email addresses.
        $value = preg_replace('/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+\.[A-Z]{2,}/i', '[redacted-email]', $value);
        // IPv4 addresses.
        $value = preg_replace('/\b(?:\d{1,3}\.){3}\d{1,3}\b/', '[redacted-ip]', $value);
        // Common phone-like strings.
        $value = preg_replace('/(?<!\d)(?:\+?\d[\d\s().\-]{7,}\d)(?!\d)/', '[redacted-phone]', $value);
        // Bearer/API keys.
        $value = preg_replace('/\b(?:sk|pk|zk|zy|aift)_[A-Za-z0-9_\-]{16,}\b/', '[redacted-key]', $value);
        $value = preg_replace('/Bearer\s+[A-Za-z0-9._\-]+/i', 'Bearer [redacted-token]', $value);

        // Do not send long raw HTML/content blobs to AI by accident.
        $value = sanitize_textarea_field($value);
        if (strlen($value) > 4000) {
            $value = substr($value, 0, 4000) . '… [truncated]';
        }

        if ($value !== $original) {
            self::$redacted_count++;
        }

        return $value;
    }
}
