<?php
/**
 * fampay_gmail_api.php
 *
 * Same job as auth/fampay_mail_check.php (find the "money received" FamPay
 * mail matching an order's amount and return its UTR) but for accounts
 * connected via Google OAuth. Uses the Gmail REST API over cURL instead of
 * IMAP + App Password, because raw IMAP XOAUTH2 support depends on the
 * server's c-client build and can't be relied on across shared hosting.
 *
 * Usage:
 *   $accessToken = google_oauth_get_valid_access_token($conn, $fampayRow, $site_settings);
 *   $found = fampay_check_payment_oauth($accessToken, $amount, $order_id, $utr_entered, null, $since_timestamp, $conn);
 *
 * IMPORTANT: pass $conn so a single "money received" mail can never be
 * matched to more than one order (see the UTR-reuse guard below).
 */

function fampay_gmail_api_get($url, $access_token) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . $access_token]);
    curl_setopt($ch, CURLOPT_TIMEOUT, 15);
    $response = curl_exec($ch);
    curl_close($ch);
    $decoded = json_decode($response, true);
    return is_array($decoded) ? $decoded : null;
}

/**
 * Recursively pulls text/plain (falls back to text/html) out of a Gmail
 * API message payload and returns it as plain decoded text.
 */
function fampay_gmail_extract_body($payload) {
    if (empty($payload)) {
        return '';
    }

    $mimeType = $payload['mimeType'] ?? '';
    $bodyData = $payload['body']['data'] ?? null;

    if ($bodyData && ($mimeType === 'text/plain' || $mimeType === 'text/html')) {
        $decoded = base64_decode(strtr($bodyData, '-_', '+/'));
        return $mimeType === 'text/html' ? strip_tags($decoded) : $decoded;
    }

    if (!empty($payload['parts'])) {
        // Prefer text/plain part if present, else fall back to text/html.
        $plain = '';
        $html = '';
        foreach ($payload['parts'] as $part) {
            $childType = $part['mimeType'] ?? '';
            if ($childType === 'text/plain' && !empty($part['body']['data'])) {
                $plain .= base64_decode(strtr($part['body']['data'], '-_', '+/'));
            } elseif ($childType === 'text/html' && !empty($part['body']['data'])) {
                $html .= base64_decode(strtr($part['body']['data'], '-_', '+/'));
            } elseif (!empty($part['parts'])) {
                $plain .= fampay_gmail_extract_body($part);
            }
        }
        if (trim($plain) !== '') {
            return $plain;
        }
        if (trim($html) !== '') {
            return strip_tags($html);
        }
    }

    return '';
}

function fampay_check_payment_oauth($access_token, $amount, $order_id, $utr_entered = null, $minutes_window = 30, $since_timestamp = null, $conn = null) {

    $result = [
        'matched' => false,
        'utr'     => null,
        'error'   => null,
    ];

    if (empty($access_token)) {
        $result['error'] = 'No valid Google access token.';
        return $result;
    }

    $cutoff = $since_timestamp !== null ? ($since_timestamp - 60) : strtotime("-{$minutes_window} minutes");

    // Gmail search only supports day-level granularity, so pull the last
    // day or two of FamPay mails and filter precisely by timestamp below.
    $q = 'from:famapp.in newer_than:2d';
    $listUrl = 'https://gmail.googleapis.com/gmail/v1/users/me/messages?' . http_build_query([
        'q'          => $q,
        'maxResults' => 20,
    ]);

    $list = fampay_gmail_api_get($listUrl, $access_token);
    if ($list === null) {
        $result['error'] = 'Gmail API request failed.';
        return $result;
    }
    if (isset($list['error'])) {
        $result['error'] = is_array($list['error']) ? ($list['error']['message'] ?? 'Gmail API error') : $list['error'];
        return $result;
    }

    $messages = $list['messages'] ?? [];
    $receivedPhrases = [
        'successfully received',
        'you have received',
        "you've received",
        'payment received',
        'money received',
        'received a payment',
        'received payment',
    ];

    foreach ($messages as $msgRef) {
        $msgUrl = 'https://gmail.googleapis.com/gmail/v1/users/me/messages/' . $msgRef['id'] . '?format=full';
        $msg = fampay_gmail_api_get($msgUrl, $access_token);
        if (!$msg || empty($msg['payload'])) {
            continue;
        }

        $internalDateMs = isset($msg['internalDate']) ? (int)$msg['internalDate'] : 0;
        $mailTime = intdiv($internalDateMs, 1000);
        if ($mailTime && $mailTime < $cutoff) {
            continue; // too old for this transaction
        }

        $body = fampay_gmail_extract_body($msg['payload']);
        if (trim($body) === '') {
            continue;
        }

        $looksLikeReceivedMail = false;
        foreach ($receivedPhrases as $phrase) {
            if (stripos($body, $phrase) !== false) {
                $looksLikeReceivedMail = true;
                break;
            }
        }
        if (!$looksLikeReceivedMail) {
            continue;
        }

        preg_match('/(?:₹|Rs\.?|INR)\s?([0-9]+(?:,[0-9]{2,3})*(?:\.[0-9]{1,2})?)/i', $body, $amtMatch);
        $mailAmount = isset($amtMatch[1]) ? (float) str_replace(',', '', $amtMatch[1]) : null;

        // Real UTR/reference number - widened to catch more of FamPay/UPI
        // apps' wording variants ("UPI transaction ID", "Txn No", "Ref ID"
        // etc.) since a genuine match now depends entirely on finding this.
        preg_match('/(?:UTR|UPI\s?(?:Ref(?:erence)?|Txn(?:action)?)?\s?(?:No\.?|Number|ID)?|Txn(?:\s|:)?\s?(?:ID|No\.?|Ref)?|RRN|Reference\s?(?:No\.?|Number|ID)?)[:\s]*([A-Za-z0-9]{9,22})/i', $body, $utrMatch);
        $mailUtr = isset($utrMatch[1]) ? $utrMatch[1] : null;

        $amountOk = ($mailAmount !== null && abs($mailAmount - (float)$amount) < 0.01);
        $utrOk = true;
        if (!empty($utr_entered) && $mailUtr) {
            $utrOk = (trim($utr_entered) === trim($mailUtr));
        }

        // Verification must be REAL: amount matching alone is not enough
        // proof this email is this specific payment - a genuine UTR/
        // reference extracted from the mail is required too. No synthetic
        // reference is generated here, so a match only ever happens when
        // we actually captured a real bank reference number.
        if ($amountOk && $utrOk && $mailUtr) {
            // Guard: has this exact reference already been used to mark a
            // *different* order SUCCESS? One bank credit must only ever
            // resolve one order - without this, several pending orders
            // sharing the same amount in the same time window (e.g. a
            // double-tapped Pay button) could all be matched to the same
            // single mail and all flip to SUCCESS.
            if ($conn) {
                $chk = $conn->prepare("SELECT order_id FROM orders WHERE utr = ? AND status = 'SUCCESS' AND order_id != ? LIMIT 1");
                $chk->bind_param("ss", $mailUtr, $order_id);
                $chk->execute();
                $already = $chk->get_result()->fetch_assoc();
                $chk->close();
                if ($already) {
                    continue; // this mail already resolved a different order - keep scanning
                }
            }

            $result['matched'] = true;
            $result['utr'] = $mailUtr;
            return $result;
        }
    }

    return $result;
}
