<?php
/**
 * Kiểm tra đồng ý từ máy chủ: gọi /api/v1/ext/consents/check trước khi gửi sự kiện cho Meta, Google...
 * Không cần thư viện nào (PHP 7.4+ với phần mở rộng curl).
 *
 * Đóng khi lỗi: chỉ 'allowed' là true khi API trả đúng granted: true và không kèm expired: true. Chưa có bản ghi còn hiệu lực (granted là null: chưa có, đã bị thay bằng mức hỏi lại mới hay quá hạn; 'expired' là true khi có bản ghi nhưng đã hết hiệu lực), khoá sai, hết giờ,
 * lỗi mạng, chuyển hướng, trả lời lạ... đều cho 'allowed' => false. Hàm không bao giờ ném lỗi (không làm hỏng đơn hàng của
 * bạn); lý do nằm ở 'error': null | 'invalid_arguments' | 'network' | 'timeout' | 'http' | 'invalid_response'.
 *
 * Tham số ($o): apiKey, siteId, category (necessary|functional|analytics|marketing), và consentId HOẶC refType
 * (email|phone|customer_id) + ref; tuỳ chọn baseUrl (mặc định biến môi trường WDL_BASE_URL; https, http chỉ cho
 * 127.0.0.1/localhost khi thử) và timeoutMs (mặc định 3000, tính cho cả lời gọi).
 *
 * @param array<string,mixed> $o
 * @return array{granted:?bool,allowed:bool,consentId:?string,recordedAt:?string,configVersion:?int,expired:bool,error:?string}
 */
function wdl_check_consent(array $o): array
{
    $closed = function (string $error): array {
        return ['granted' => null, 'allowed' => false, 'consentId' => null, 'recordedAt' => null, 'configVersion' => null, 'expired' => false, 'error' => $error];
    };
    try {
        $categories = ['necessary', 'functional', 'analytics', 'marketing'];
        $refTypes = ['email', 'phone', 'customer_id'];
        $apiKey = $o['apiKey'] ?? null;
        $siteId = $o['siteId'] ?? null;
        $category = $o['category'] ?? null;
        $base = array_key_exists('baseUrl', $o) ? $o['baseUrl'] : getenv('WDL_BASE_URL');
        $consentId = $o['consentId'] ?? null;
        $refType = $o['refType'] ?? null;
        $ref = $o['ref'] ?? null;
        $hasId = is_string($consentId) && $consentId !== '';
        $hasRef = $refType !== null || $ref !== null;
        $validRef = is_string($refType) && in_array($refType, $refTypes, true) && is_string($ref) && $ref !== '';
        if (
            !is_string($apiKey) || $apiKey === ''
            || !is_string($siteId) || $siteId === ''
            || !is_string($category) || !in_array($category, $categories, true)
            || !is_string($base)
            || $hasId === $hasRef
            || ($hasRef && !$validRef)
        ) {
            return $closed('invalid_arguments');
        }
        $parts = parse_url($base);
        $scheme = is_array($parts) ? ($parts['scheme'] ?? '') : '';
        $host = is_array($parts) ? ($parts['host'] ?? '') : '';
        $loopback = in_array($host, ['localhost', '127.0.0.1', '[::1]'], true);
        if ($host === '' || !($scheme === 'https' || ($scheme === 'http' && $loopback))) {
            return $closed('invalid_arguments');
        }
        // consentId đi trên URL (GET); ref (email, số điện thoại, mã khách hàng) không bao giờ nằm trên URL: đi trong thân JSON của POST.
        $url = $scheme . '://' . $host . (isset($parts['port']) ? ':' . $parts['port'] : '') . '/api/v1/ext/consents/check';
        $headers = ['Authorization: Bearer ' . $apiKey, 'Accept: application/json'];
        if ($hasId) {
            $url .= '?' . http_build_query(['siteId' => $siteId, 'category' => $category, 'consentId' => $consentId], '', '&', PHP_QUERY_RFC3986);
        } else {
            $headers[] = 'Content-Type: application/json';
        }
        $timeoutMs = (isset($o['timeoutMs']) && is_numeric($o['timeoutMs']) && $o['timeoutMs'] > 0) ? (int) $o['timeoutMs'] : 3000;

        if (!function_exists('curl_init')) {
            return $closed('network');
        }
        $ch = curl_init($url);
        if (!$hasId) {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['siteId' => $siteId, 'category' => $category, 'refType' => $refType, 'ref' => $ref]));
        }
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_FOLLOWLOCATION => false, // không bao giờ đi theo chuyển hướng (khoá API sẽ đi theo)
            CURLOPT_TIMEOUT_MS => $timeoutMs,
            CURLOPT_CONNECTTIMEOUT_MS => $timeoutMs,
            CURLOPT_NOSIGNAL => true,
            CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS,
        ]);
        $text = curl_exec($ch);
        $errno = curl_errno($ch);
        $status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        curl_close($ch);
        if ($text === false || $errno !== 0) {
            return $closed($errno === 28 ? 'timeout' : 'network'); // 28 = CURLE_OPERATION_TIMEDOUT
        }
        if ($status < 200 || $status > 299) {
            return $closed('http');
        }
        if (!is_string($text) || strlen($text) > 65536) {
            return $closed('invalid_response');
        }
        $body = json_decode($text, true, 8);
        if (!is_array($body) || !array_key_exists('granted', $body) || !($body['granted'] === null || is_bool($body['granted']))) {
            return $closed('invalid_response');
        }
        return [
            'granted' => $body['granted'],
            'allowed' => $body['granted'] === true && ($body['expired'] ?? false) !== true,
            'consentId' => isset($body['consentId']) && is_string($body['consentId']) ? $body['consentId'] : null,
            'recordedAt' => isset($body['recordedAt']) && is_string($body['recordedAt']) ? $body['recordedAt'] : null,
            'configVersion' => isset($body['configVersion']) && is_int($body['configVersion']) ? $body['configVersion'] : null,
            'expired' => ($body['expired'] ?? false) === true,
            'error' => null,
        ];
    } catch (\Throwable $e) {
        return $closed('network');
    }
}
