<?php
// --- 0) LOG FIRST — BEFORE any includes; read body ONCE ---
$raw = file_get_contents('php://input');
$headers = function_exists('getallheaders') ? getallheaders() : [];
$logDir = __DIR__ . '/logs';
if (!is_dir($logDir))
    @mkdir($logDir, 0777, true);

// logger
$log = function (string $fname, string $line) use ($logDir) {
    @file_put_contents($logDir . '/' . $fname, date('c') . ' ' . $line . "\n", FILE_APPEND);
};
$log(
    'fb_webhook.log',
    ($_SERVER['REQUEST_METHOD'] ?? '') . ' ' . ($_SERVER['REQUEST_URI'] ?? '') .
        ' IP:' . ($_SERVER['REMOTE_ADDR'] ?? '') . "\n" .
        'Headers:' . json_encode($headers) . "\n" .
        'Body:' . $raw . "\n"
);


include_once __DIR__ . '/../global.php';
$fb = new FacebookIntegration();

// --- 2) Verify (GET) ---
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'GET') {
    $verifyToken = $fb->getSetting('fb_verify_token', '');
    if (
        isset($_GET['hub_mode'], $_GET['hub_verify_token'], $_GET['hub_challenge'])
        && $_GET['hub_mode'] === 'subscribe'
        && hash_equals($verifyToken, $_GET['hub_verify_token'])
    ) {
        header('Content-Type: text/plain');
        echo $_GET['hub_challenge'];
        exit;
    }
    http_response_code(403);
    echo 'Forbidden';
    exit;
}

/* ===================== 3) SIGNATURE CHECK (HARDENED) ===================== */
$appId = (string) $fb->getSetting('fb_app_id', '');
$appSecret = (string) $fb->getSetting('fb_app_secret', '');

// Normalise stored secret
$appSecret = html_entity_decode($appSecret, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$appSecret = trim($appSecret);
if (
    (substr($appSecret, 0, 1) === '"' && substr($appSecret, -1) === '"') ||
    (substr($appSecret, 0, 1) === "'" && substr($appSecret, -1) === "'")
) {
    $appSecret = substr($appSecret, 1, -1);
}
// If secret is 16 bytes of binary, convert back to 32-char hex
if (strlen($appSecret) === 16 && preg_match('/[^\x20-\x7E]/', $appSecret)) {
    $appSecret = bin2hex($appSecret);
}

$hdrSig = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';
if (!empty($appSecret) && !empty($hdrSig)) {
    $calc = 'sha256=' . hash_hmac('sha256', $raw, $appSecret);
    if (!hash_equals($calc, $hdrSig)) {
        $log(
            'fb_webhook.log',
            'signature_mismatch app_id=' . $appId .
                ' secret_len=' . strlen($appSecret) .
                ' secret_md5=' . md5($appSecret) .
                ' expected=' . $calc .
                ' got=' . $hdrSig
        );
        http_response_code(401);
        echo 'Invalid signature';
        exit;
    }
}
/* ======================================================================== */

// --- 4) Parse JSON ---
$payload = json_decode($raw, true);
if (json_last_error() !== JSON_ERROR_NONE) {
    $log('fb_webhook.log', 'json_error=' . json_last_error_msg());
    http_response_code(200);
    echo 'OK';
    exit;
}
if (empty($payload['entry'])) {
    http_response_code(200);
    echo 'OK';
    exit;
}

// --- 5) Return 200 ASAP, then continue work ---
http_response_code(200);
header('Content-Type: text/plain');
echo 'OK';
$log('fb_webhook.log', 'returned 200');
if (function_exists('fastcgi_finish_request'))
    @fastcgi_finish_request();

// --- 6) Fetch & insert ---
$pageToken = $fb->getSetting('fb_page_access_token', '');

// Diagnostics BEFORE normalization
$log('fb_webhook.log', 'page_token_len=' . strlen($pageToken) . ' printable=' . (preg_match('/^[\x20-\x7E]+$/', $pageToken) ? 'yes' : 'no'));

// Normalise token: decode HTML entities, strip whitespace & non-printables
$pageToken = html_entity_decode($pageToken, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$pageToken = preg_replace("/\s+/", "", $pageToken);          // remove spaces/newlines/tabs
$pageToken = preg_replace('/[^\x20-\x7E]/', '', $pageToken); // remove non-printable bytes
$pageToken = trim($pageToken);

// Diagnostics AFTER normalization
$log('fb_webhook.log', 'page_token_normalized_len=' . strlen($pageToken) . ' printable=' . (preg_match('/^[\x20-\x7E]+$/', $pageToken) ? 'yes' : 'no'));

if (empty($pageToken)) {
    $log('fb_webhook.log', 'error: empty page token after normalization');
    return;
}

try {
    foreach ($payload['entry'] as $entry) {
        foreach (($entry['changes'] ?? []) as $change) {
            if (($change['field'] ?? '') !== 'leadgen')
                continue;

            $leadId = $change['value']['leadgen_id'] ?? null;
            $formId = $change['value']['form_id'] ?? null;
            $pageId = $change['value']['page_id'] ?? ($entry['id'] ?? null);
            if (!$leadId) {
                $log('fb_webhook.log', 'warning: no leadgen_id');
                continue;
            }

            // appsecret_proof for the page token
            $appSecret = $fb->getSetting('fb_app_secret', '');
            $proof = !empty($appSecret) ? hash_hmac('sha256', $pageToken, $appSecret) : '';

            // Fetch lead details
            $resp = $fb->fbGetLead($leadId, $pageToken, $proof);
            $log('fb_graph.log', "lead_id={$leadId} resp=" . json_encode($resp));

            if (isset($resp['error'])) {
                $log('fb_webhook.log', 'graph_error lead_id=' . $leadId . ' ' . json_encode($resp['error']));
                continue;
            }

            $fieldData = $resp['field_data'] ?? [];
            if (empty($fieldData)) {
                $log('fb_webhook.log', 'no_field_data lead_id=' . $leadId);
                continue;
            }

            // Insert into CRM
            $fb->insertLeadFromFacebookFields($fieldData, [
                'fb_page_id' => $pageId,
                'fb_form_id' => $formId,
                'fb_lead_id' => $leadId,
                'created_time' => $change['value']['created_time'] ?? null,
                '_raw' => $resp
            ]);
            $log('fb_webhook.log', 'inserted lead_id=' . $leadId);
        }
    }
} catch (Throwable $e) {
    $log('fb_webhook.log', 'exception ' . $e->getMessage());
}
