<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once 'vendor/autoload.php';
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Signer\Ecdsa\Sha256;
use Lcobucci\JWT\Validation\Constraint\SignedWith;

use Google\Client;

// Database configuration (adjust as needed)
$dbHost = '136.112.153.136';
$dbUser = 'lac';
$dbPass = 'kschhiKHSH23243#';
$dbName = 'lac_prod';

$mysqli = mysqli_connect($dbHost, $dbUser, $dbPass, $dbName);
if (mysqli_connect_errno()) {
    error_log("Database connection failed: " . mysqli_connect_error(), 3, $errorLog);
    http_response_code(500);
    die('Database connection failed');
}

// Configuration
$logDir = __DIR__ . '/logs/'; // Script directory: /var/www/html/altb_reports/public/reco-script/
$payloadLog = $logDir . 'rtdn_payload.log';
$decodedLog = $logDir . 'rtdn_decoded.log';
$transactionLog = $logDir . 'transaction.log';
$errorLog = $logDir . 'rtdn_error.log';
$certRawLog = $logDir . 'certificate_raw.log';
$certFormattedLog = $logDir . 'certificate_formatted.log';
$keyDetailsLog = $logDir . 'key_details.log';
$publicKeyLog = $logDir . 'public_key.log';
$jwtHeaderLog = $logDir . 'jwt_header.log';
$chainVerifyLog = $logDir . 'chain_verify.log';
$jwtVerifyLog = $logDir . 'jwt_verify.log';
$subscriptionUpdateLog = $logDir . 'subscription_update.log';
$signedTransactionTraceLog = $logDir . 'signed_transaction_trace.log';

// Check directory writability
if (!is_writable($logDir)) {
    http_response_code(500);
    die('Log directory is not writable: ' . $logDir);
}

// Get JWT from POST body
$rawInput = file_get_contents("php://input");
file_put_contents($logDir . 'debug_raw_input.log', "RAW: " . $rawInput . PHP_EOL, FILE_APPEND);

// Decode JSON input
$data = json_decode($rawInput, true);
if (!isset($data['signedPayload'])) {
    file_put_contents($payloadLog, "Missing signedPayload: $rawInput" . PHP_EOL, FILE_APPEND);
    http_response_code(400);
    echo 'Missing signedPayload';
    exit;
}

$jwt = $data['signedPayload'];
$parts = explode('.', $jwt);
if (count($parts) !== 3) {
    file_put_contents($payloadLog, "Malformed JWT: $jwt" . PHP_EOL, FILE_APPEND);
    http_response_code(400);
    echo 'Malformed JWT';
    exit;
}

list($headerEncoded, $payloadEncoded, $signatureEncoded) = $parts;

// Decode header and payload
$headerRaw = base64_decode(strtr($headerEncoded, '-_', '+/'));
$payloadRaw = base64_decode(strtr($payloadEncoded, '-_', '+/'));
if (!$headerRaw || !$payloadRaw) {
    error_log("Base64 decoding failed for header or payload", 3, $errorLog);
    http_response_code(400);
    echo 'JWT Decode Error';
    exit;
}

$header = json_decode($headerRaw, true);
$payload = json_decode($payloadRaw, true);
if (!$header || !$payload) {
    error_log("JSON decoding failed: header or payload is null", 3, $errorLog);
    http_response_code(400);
    echo 'Invalid JWT';
    exit;
}

// Log decoded payload (exclude sensitive data)
$safePayload = array_diff_key($payload, ['data' => 1]);
file_put_contents($decodedLog, print_r($safePayload, true) . PHP_EOL, FILE_APPEND);

// Log JWT header
file_put_contents($jwtHeaderLog, print_r($header, true) . PHP_EOL, FILE_APPEND);

// Verify JWT Signature
try {
    $x5c = $header['x5c'] ?? [];
    if (empty($x5c)) {
        error_log("Missing x5c certificate chain", 3, $errorLog);
        http_response_code(400);
        die('Missing x5c');
    }

    // Verify algorithm
    if (!isset($header['alg']) || $header['alg'] !== 'ES256') {
        error_log("Invalid or missing algorithm: " . ($header['alg'] ?? 'none'), 3, $errorLog);
        http_response_code(400);
        die('Invalid JWT algorithm: ' . ($header['alg'] ?? 'none'));
    }

    // Decode leaf certificate
    $certData = base64_decode($x5c[0], true);
    if ($certData === false) {
        error_log("Invalid Base64 encoding in x5c[0]: " . substr($x5c[0], 0, 50) . "...", 3, $errorLog);
        http_response_code(400);
        die('Invalid Base64 in x5c[0]');
    }

    // Check if decoded data resembles a DER certificate
    if (strlen($certData) < 100 || !preg_match('/^\x30[\x80-\x8f]/', $certData)) {
        error_log("Decoded x5c[0] is not a valid DER certificate, length: " . strlen($certData), 3, $errorLog);
        file_put_contents($certRawLog, $x5c[0] . PHP_EOL, FILE_APPEND);
        http_response_code(400);
        die('Invalid DER certificate in x5c[0]');
    }

    // Log raw x5c[0]
    file_put_contents($certRawLog, $x5c[0] . PHP_EOL, FILE_APPEND);

    // Construct PEM certificate
    $cert = "-----BEGIN CERTIFICATE-----\n" . chunk_split(base64_encode($certData), 64, "\n") . "-----END CERTIFICATE-----";
    file_put_contents($certFormattedLog, $cert . PHP_EOL, FILE_APPEND);

    // Write certificate to file
    $certFile = $logDir . 'test_cert.pem';
    if (!file_put_contents($certFile, $cert)) {
        error_log("Failed to write certificate to $certFile: Permission denied", 3, $errorLog);
        http_response_code(500);
        die('Failed to write certificate file');
    }

    // Validate certificate
    exec("openssl x509 -in " . escapeshellarg($certFile) . " -text -noout 2>&1", $output, $returnCode);
    if ($returnCode !== 0) {
        error_log("Certificate validation failed: " . implode("\n", $output), 3, $errorLog);
        http_response_code(400);
        die('Invalid certificate: ' . implode("\n", $output));
    }

    // Validate certificate chain
    $intermediateCert = "-----BEGIN CERTIFICATE-----\n" . chunk_split($x5c[1], 64, "\n") . "-----END CERTIFICATE-----";
    $rootCert = "-----BEGIN CERTIFICATE-----\n" . chunk_split($x5c[2], 64, "\n") . "-----END CERTIFICATE-----";
    file_put_contents($logDir . 'intermediate_cert.pem', $intermediateCert);
    file_put_contents($logDir . 'root_cert.pem', $rootCert);

    exec("openssl verify -CAfile " . escapeshellarg($logDir . 'intermediate_cert.pem') . " " . escapeshellarg($certFile) . " 2>&1", $verifyOutput, $verifyReturnCode);
    if ($verifyReturnCode !== 0) {
        error_log("Certificate chain validation failed: " . implode("\n", $verifyOutput), 3, $errorLog);
    } else {
        file_put_contents($chainVerifyLog, "Chain validation succeeded: " . implode("\n", $verifyOutput) . PHP_EOL, FILE_APPEND);
    }

    // Get public key
    $publicKey = openssl_pkey_get_public($cert);
    if (!$publicKey) {
        $error = openssl_error_string();
        error_log("Failed to extract public key: $error", 3, $errorLog);
        http_response_code(400);
        die('Failed to extract public key: ' . $error);
    }

    // Get key details
    $keyDetails = openssl_pkey_get_details($publicKey);
    file_put_contents($keyDetailsLog, print_r($keyDetails, true) . PHP_EOL, FILE_APPEND);

    if (!isset($keyDetails['ec']) || !isset($keyDetails['ec']['curve_name']) || $keyDetails['ec']['curve_name'] !== 'prime256v1') {
        error_log("Public key is not an EC key with P-256 curve, found: " . ($keyDetails['ec']['curve_name'] ?? 'none'), 3, $errorLog);
        http_response_code(400);
        die('Public key is not an EC key with P-256 curve');
    }

    // Export public key to PEM format
    $publicKeyPem = $keyDetails['key'];
    file_put_contents($publicKeyLog, $publicKeyPem . PHP_EOL, FILE_APPEND);

    // Verify JWT with lcobucci/jwt
    $signer = new Sha256();
    $config = Configuration::forAsymmetricSigner(
        $signer,
        InMemory::plainText('unused'),
        InMemory::plainText($publicKeyPem)
    );
    $token = $config->parser()->parse($jwt);
    $constraint = new SignedWith($signer, InMemory::plainText($publicKeyPem));
    if (!$config->validator()->validate($token, $constraint)) {
        error_log("Lcobucci JWT verification failed", 3, $errorLog);
        http_response_code(401);
        die('JWT Verification Failed');
    }
    file_put_contents($jwtVerifyLog, "Lcobucci JWT verification succeeded" . PHP_EOL, FILE_APPEND);

    // Direct OpenSSL verification for debugging
    $data = $headerEncoded . '.' . $payloadEncoded;
    $signature = base64_decode(strtr($signatureEncoded, '-_', '+/'));
    if ($signature === false) {
        error_log("Invalid Base64 in JWT signature", 3, $errorLog);
        http_response_code(400);
        die('Invalid Base64 in JWT signature');
    }
    $verified = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);
    if ($verified !== 1) {
        $error = $verified === 0 ? 'Signature verification failed' : 'OpenSSL error: ' . openssl_error_string();
        error_log("Direct OpenSSL verification failed: $error", 3, $errorLog);
        file_put_contents($logDir . 'openssl_verify.log', "Direct OpenSSL verification failed: $error" . PHP_EOL, FILE_APPEND);
    } else {
        file_put_contents($logDir . 'openssl_verify.log', "Direct OpenSSL verification succeeded" . PHP_EOL, FILE_APPEND);
    }

} catch (Exception $e) {
    error_log("JWT verification failed: " . $e->getMessage(), 3, $errorLog);
    http_response_code(401);
    echo 'JWT Verification Failed: ' . $e->getMessage();
    exit;
}

// Extract key values
$notificationType = $payload['notificationType'] ?? '';
$subType = $payload['subtype'] ?? '';
$signedTransactionInfo = $payload['data']['signedTransactionInfo'] ?? '';


// Decode and verify signedTransactionInfo
$transactionPayload = [];
if ($signedTransactionInfo) {
    try {
        list($tHeaderEncoded, $tPayloadEncoded, $tSignatureEncoded) = explode('.', $signedTransactionInfo);
        $tHeader = json_decode(base64_decode(strtr($tHeaderEncoded, '-_', '+/')), true);
        $transactionPayload = json_decode(base64_decode(strtr($tPayloadEncoded, '-_', '+/')), true);

        $tX5c = $tHeader['x5c'] ?? [];
        if (empty($tX5c)) {
            error_log("Missing x5c in signedTransactionInfo", 3, $errorLog);
            throw new Exception('Missing x5c in signedTransactionInfo');
        }

        $tCertData = base64_decode($tX5c[0], true);
        if ($tCertData === false) {
            error_log("Invalid Base64 in signedTransactionInfo x5c[0]: " . substr($tX5c[0], 0, 50) . "...", 3, $errorLog);
            throw new Exception('Invalid Base64 in signedTransactionInfo x5c[0]');
        }

        if (strlen($tCertData) < 100 || !preg_match('/^\x30[\x80-\x8f]/', $tCertData)) {
            error_log("Invalid DER certificate in signedTransactionInfo x5c[0]", 3, $errorLog);
            throw new Exception('Invalid DER certificate in signedTransactionInfo x5c[0]');
        }

        $tCert = "-----BEGIN CERTIFICATE-----\n" . chunk_split(base64_encode($tCertData), 64, "\n") . "-----END CERTIFICATE-----";
        file_put_contents($logDir . 'transaction_cert_formatted.log', $tCert . PHP_EOL, FILE_APPEND);

        $tPublicKey = openssl_pkey_get_public($tCert);
        if (!$tPublicKey) {
            $error = openssl_error_string();
            error_log("Failed to extract public key for signedTransactionInfo: $error", 3, $errorLog);
            throw new Exception('Failed to extract public key for signedTransactionInfo: ' . $error);
        }

        $tKeyDetails = openssl_pkey_get_details($tPublicKey);
        file_put_contents($logDir . 'transaction_key_details.log', print_r($tKeyDetails, true) . PHP_EOL, FILE_APPEND);

        if (!isset($tKeyDetails['ec']) || !isset($tKeyDetails['ec']['curve_name']) || $tKeyDetails['ec']['curve_name'] !== 'prime256v1') {
            error_log("Public key for signedTransactionInfo is not an EC key with P-256 curve", 3, $errorLog);
            throw new Exception('Public key for signedTransactionInfo is not an EC key with P-256 curve');
        }

        $tPublicKeyPem = $tKeyDetails['key'];
        file_put_contents($logDir . 'transaction_public_key.log', $tPublicKeyPem . PHP_EOL, FILE_APPEND);

        // Verify signedTransactionInfo with lcobucci/jwt
        $tConfig = Configuration::forAsymmetricSigner(
            new Sha256(),
            InMemory::plainText('unused'),
            InMemory::plainText($tPublicKeyPem)
        );
        $tToken = $tConfig->parser()->parse($signedTransactionInfo);
        $tConstraint = new SignedWith(new Sha256(), InMemory::plainText($tPublicKeyPem));
        if (!$tConfig->validator()->validate($tToken, $tConstraint)) {
            error_log("Lcobucci signedTransactionInfo verification failed", 3, $errorLog);
            throw new Exception('signedTransactionInfo verification failed');
        }
        file_put_contents($logDir . 'transaction_jwt_verify.log', "Lcobucci signedTransactionInfo verification succeeded" . PHP_EOL, FILE_APPEND);

        // Log transaction payload
        //print_r($transactionPayload);
        file_put_contents($transactionLog, print_r($transactionPayload, true) . PHP_EOL, FILE_APPEND);

        $signedTransactionTrace = [
            'logged_at' => date('Y-m-d H:i:s'),
            'notification_type' => $notificationType,
            'sub_type' => $subType,
            'transaction_id' => $transactionPayload['transactionId'] ?? '',
            'original_transaction_id' => $transactionPayload['originalTransactionId'] ?? '',
            'app_account_token' => $transactionPayload['appAccountToken'] ?? '',
            'signed_transaction_info_sha256' => hash('sha256', $signedTransactionInfo),
            'signed_transaction_info' => $signedTransactionInfo,
        ];
        file_put_contents($signedTransactionTraceLog, json_encode($signedTransactionTrace, JSON_UNESCAPED_SLASHES) . PHP_EOL, FILE_APPEND);

        // yaha pr webhook_itunes is table me insert bhi kr do $transactionPayload isko 
							 $insertWebhookSql = "INSERT INTO webhook_itunes (
							transaction_id,
							original_transaction_id,
							web_order_line_item_id,
							bundle_id,
							product_id,
							subscription_group_identifier,
							purchase_date,
							original_purchase_date,
							expires_date,
							quantity,
							type,
							app_account_token,
							in_app_ownership_type,
							signed_date,
							environment,
							transaction_reason,
							storefront,
							storefront_id,
							price,
							currency,
							app_transaction_id
						) VALUES (
							'".mysqli_real_escape_string($mysqli, $transactionPayload['transactionId'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['originalTransactionId'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['webOrderLineItemId'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['bundleId'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['productId'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['subscriptionGroupIdentifier'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['purchaseDate'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['originalPurchaseDate'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['expiresDate'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['quantity'] ?? 1)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['type'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['appAccountToken'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['inAppOwnershipType'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['signedDate'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['environment'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['transactionReason'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['storefront'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['storefrontId'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, isset($transactionPayload['price']) ? ($transactionPayload['price'] / 1000) : null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['currency'] ?? null)."',
							'".mysqli_real_escape_string($mysqli, $transactionPayload['appTransactionId'] ?? null)."'
						)";

						if (!mysqli_query($mysqli, $insertWebhookSql)) {
							error_log("Webhook insert failed: " . mysqli_error($mysqli), 3, $errorLog);
							echo "Webhook insert failed:". mysqli_error($mysqli);
							file_put_contents($transactionLog, "Webhook insert failed: " . mysqli_error($mysqli) . PHP_EOL, FILE_APPEND);
						} else {
							file_put_contents($transactionLog, "Webhook inserted for txn: " . ($transactionPayload['transactionId'] ?? '') . PHP_EOL, FILE_APPEND);
						}
								

        // Process subscription renewal
        $originalTransactionId = $transactionPayload['originalTransactionId'] ?? null;
        $notificationRenwalType = $transactionPayload['transactionReason'] ?? null;
        $appAccountToken = $transactionPayload['appAccountToken'] ?? null;
        $expiresDate = isset($transactionPayload['expiresDate']) ? (int)($transactionPayload['expiresDate'] / 1000) : null;
        $currentDate = (new DateTime('now', new DateTimeZone('Asia/Kolkata')))->getTimestamp(); // IST
        $expiresDateFormatted = $expiresDate ? date('Y-m-d H:i:s', $expiresDate) : null;
        $purchaseDate = isset($transactionPayload['purchaseDate']) ? date('Y-m-d H:i:s', (int)($transactionPayload['purchaseDate'] / 1000)) : null;
        $transactionId = $transactionPayload['transactionId'] ?? null;
        $productId = $transactionPayload['productId'] ?? null;
        $price = isset($transactionPayload['price']) ? number_format($transactionPayload['price'] / 1000, 2, '.', '') : null; // Convert micros to dollars
        $currency = $transactionPayload['currency'] ?? 'USD';
        $isFreeTrial = (($transactionPayload['offerDiscountType'] ?? '') === 'FREE_TRIAL') ? 1 : 0;
        $pgPaymentData = json_encode($transactionPayload);
        
         //echo $expiresDate."====".$currentDate;
        
	        if (
	            $notificationType === 'DID_CHANGE_RENEWAL_STATUS'
	            && $subType === 'AUTO_RENEW_DISABLED'
	            && $originalTransactionId
	        ) {
	            $cancelledAt = format_ist_now();
	            $cancelledRow = fetch_latest_subscription_by_gateway_subscription_id($mysqli, $originalTransactionId);
	            if ($cancelledRow) {
	                $cancelSql = "UPDATE tbl_customer_subscriptions SET is_cancelled='1', cancelled_at='" . mysqli_real_escape_string($mysqli, $cancelledAt) . "' WHERE id='" . (int)$cancelledRow['id'] . "' LIMIT 1";
	                if (mysqli_query($mysqli, $cancelSql)) {
	                    file_put_contents($subscriptionUpdateLog, "Marked subscription cancelled: subscription_id=" . ($cancelledRow['id'] ?? '') . ", gateway_subscription_id=$originalTransactionId, cancelled_at=$cancelledAt" . PHP_EOL, FILE_APPEND);
	                } else {
	                    error_log("Cancel update failed: " . mysqli_error($mysqli), 3, $errorLog);
	                    file_put_contents($subscriptionUpdateLog, "Cancel update failed for gateway_subscription_id=$originalTransactionId: " . mysqli_error($mysqli) . PHP_EOL, FILE_APPEND);
	                }
	            } else {
	                file_put_contents($subscriptionUpdateLog, "Cancel update skipped: no subscription found for gateway_subscription_id=$originalTransactionId" . PHP_EOL, FILE_APPEND);
	            }
	        } else if ($originalTransactionId && $expiresDate && $productId) {
          
            // Fetch latest subscription record
             $query = "SELECT * FROM tbl_customer_subscriptions WHERE gateway_subscription_id = '" . mysqli_real_escape_string($mysqli, $originalTransactionId) . "' AND autorenew='1' ORDER BY created DESC LIMIT 1";
            $result = mysqli_query($mysqli, $query);
            if (!$result) {
                error_log("Query failed: " . mysqli_error($mysqli), 3, $errorLog);
                file_put_contents($subscriptionUpdateLog, "Query failed for gateway_subscription_id=$originalTransactionId: " . mysqli_error($mysqli) . PHP_EOL, FILE_APPEND);
                http_response_code(500);
                die('Database query failed');
            }

	            $RenewRow = mysqli_fetch_assoc($result);
	             //echo '<pre>'; print_r($RenewRow);

	             if ($RenewRow && ($RenewRow['status'] == '2' || $RenewRow['status'] == '3')) {
	                $id = (int)$RenewRow['id'];
	                $crt_date = date('Y-m-d H:i:s');
	                //echo $purchaseDate;
	                $exp_query = "UPDATE tbl_customer_subscriptions SET status = '7' , end_date = '$crt_date'  WHERE id = $id AND status IN ('2','3') AND (end_date < NOW() OR date(end_date) ='".date('Y-m-d', strtotime($purchaseDate))."') ";
	                mysqli_query($mysqli, $exp_query);
	                if (mysqli_affected_rows($mysqli) > 0) {
	                    $RenewRow['status'] = '7';
	                }
	            }

	            
	            if ($RenewRow && $RenewRow['status'] == '7') {
	                $existingRenewalRow = fetch_subscription_by_transaction_id($mysqli, $transactionId);
	                if ($existingRenewalRow) {
	                    file_put_contents($subscriptionUpdateLog, "Skipped renewal insert: transaction_id=$transactionId already exists with subscription_id=" . ($existingRenewalRow['id'] ?? '') . PHP_EOL, FILE_APPEND);
	                } else {
	                    list($renewOrderRow, $renewOrderDetailRow) = fetch_order_context($mysqli, (int)($RenewRow['order_id'] ?? 0));
	                    if ($renewOrderRow && $renewOrderDetailRow) {
	                        $insertRenewalQuery = build_subscription_insert_sql_from_order(
	                            $mysqli,
	                            $renewOrderRow,
	                            $renewOrderDetailRow,
	                            [
	                                'transaction_id' => $transactionId,
	                                'gateway_subscription_id' => $originalTransactionId,
	                                'pg_payment_data' => $pgPaymentData,
	                                'price' => $price,
	                                'currency' => $currency,
	                                'purchase_date' => $purchaseDate,
	                                'expires_date' => $expiresDateFormatted,
	                                'is_free_trial' => $isFreeTrial,
	                                'product_id' => $productId,
	                                'purchase_type' => 'RENEWED',
	                                'recurring' => 1,
	                            ]
	                        );

	                        file_put_contents($subscriptionUpdateLog, "Insert Query: $insertRenewalQuery" . PHP_EOL, FILE_APPEND);
	                        if (mysqli_query($mysqli, $insertRenewalQuery)) {
								echo "Record Inserted";
	                            file_put_contents($subscriptionUpdateLog, "Inserted renewal: gateway_subscription_id=$originalTransactionId, transaction_id=$transactionId, status=2, end_date=$expiresDateFormatted" . PHP_EOL, FILE_APPEND);

	                            // $updateOrderSql = "UPDATE tbl_order SET payment_status='2', order_status='2' WHERE id='".$RenewRow['order_id']."'";
	                            // mysqli_query($mysqli, $updateOrderSql);

	                            ################################## FIREBASE NOTIFICATION #########################################
	                            /**$deviceQuery = "SELECT push_device_token, device_type FROM customer_device WHERE user_id='" . $renewOrderRow['subscriber_id'] . "'";
	                            $result = mysqli_query($mysqli, $deviceQuery);
	                            if ($result && mysqli_num_rows($result) > 0) {
	                                while ($deviceRow = mysqli_fetch_assoc($result)) {
	                                    $DeviceID = $deviceRow['push_device_token'];
	                                    $device   = $deviceRow['device_type']; // e.g., 'mobile', 'tv', 'ios'
	                                    if ($DeviceID) {
	                                        $notificationSent = SendPurchaseSuccessFCMNotification($DeviceID, $device);
	                                        if ($notificationSent) {
	                                            error_log("FCM Purchase Success sent successfully for user ID " . $renewOrderRow['subscriber_id'] . ", device $device\n", 3, $errorLog);
	                                        } else {
	                                            error_log("FCM Purchase Success failed for user ID " . $renewOrderRow['subscriber_id'] . ", device $device\n", 3, $errorLog);
	                                        }
	                                    }
	                                }
	                            } else {
	                                error_log("No device found for user ID " . $renewOrderRow['subscriber_id'], 3, $errorLog);
	                            }  **/
	                            ################################### FIREBASE NOTIFICATION #########################################

	                        } else {
	                            error_log("Insert failed: " . mysqli_error($mysqli), 3, $errorLog);
	                            file_put_contents($subscriptionUpdateLog, "Insert failed for gateway_subscription_id=$originalTransactionId: " . mysqli_error($mysqli) . PHP_EOL, FILE_APPEND);
	                        }
	                    } else {
	                        file_put_contents($subscriptionUpdateLog, "Skipped renewal insert: order/order_details missing for order_id=" . ($RenewRow['order_id'] ?? '') . PHP_EOL, FILE_APPEND);
	                    }
	                }
	            } else if(isset($appAccountToken) && $appAccountToken != '') {
	                $existingOneTimeRow = fetch_subscription_by_transaction_id($mysqli, $transactionId);
	                if ($existingOneTimeRow) {
	                    file_put_contents($subscriptionUpdateLog, "Skipped one-time insert: transaction_id=$transactionId already exists with subscription_id=" . ($existingOneTimeRow['id'] ?? '') . PHP_EOL, FILE_APPEND);
	                } else {
	                    $chkOrderSql = "SELECT * FROM tbl_order WHERE gateway_consent_id='" . mysqli_real_escape_string($mysqli, $appAccountToken) . "' AND order_status='2' ORDER BY id DESC LIMIT 1";
	                    $chkResult = mysqli_query($mysqli, $chkOrderSql);
	                    $chkOrderRow = mysqli_fetch_assoc($chkResult);
	                    if(!empty($chkOrderRow)){
	                        list($resolvedOrderRow, $chkOrderDetailRow) = fetch_order_context($mysqli, (int)$chkOrderRow['id']);
	                        if(!empty($resolvedOrderRow) && !empty($chkOrderDetailRow)){
	                            $insertQuery = build_subscription_insert_sql_from_order(
	                                $mysqli,
	                                $resolvedOrderRow,
	                                $chkOrderDetailRow,
	                                [
	                                    'transaction_id' => $transactionId,
	                                    'gateway_subscription_id' => $originalTransactionId,
	                                    'pg_payment_data' => $pgPaymentData,
	                                    'price' => $price,
	                                    'currency' => $currency,
	                                    'purchase_date' => $purchaseDate,
	                                    'expires_date' => $expiresDateFormatted,
	                                    'is_free_trial' => $isFreeTrial,
	                                    'product_id' => $productId,
	                                    'purchase_type' => 'PURCHASED',
	                                    'recurring' => 1,
	                                ]
	                            );

	                            file_put_contents($subscriptionUpdateLog, "Insert Query: $insertQuery" . PHP_EOL, FILE_APPEND);
	                            if (mysqli_query($mysqli, $insertQuery)) {
	                                $updateOrderSql = "UPDATE tbl_order SET payment_status='2', order_status='2' WHERE id='".$resolvedOrderRow['id']."'";
	                                mysqli_query($mysqli, $updateOrderSql);

	                                ################################## FIREBASE NOTIFICATION #########################################
	                                $deviceQuery = "SELECT push_device_token, device_type FROM customer_device WHERE user_id='" . $resolvedOrderRow['subscriber_id'] . "'";
	                                $result = mysqli_query($mysqli, $deviceQuery);
	                                if ($result && mysqli_num_rows($result) > 0) {
	                                    while ($deviceRow = mysqli_fetch_assoc($result)) {
	                                        $DeviceID = $deviceRow['push_device_token'];
	                                        $device   = $deviceRow['device_type']; // e.g., 'mobile', 'tv', 'ios'
	                                        if ($DeviceID) {
	                                            $notificationSent = SendPurchaseSuccessFCMNotification($DeviceID, $device);
	                                            if ($notificationSent) {
	                                                error_log("FCM Purchase Success sent successfully for user ID " . $resolvedOrderRow['subscriber_id'] . ", device $device\n", 3, $errorLog);
	                                            } else {
	                                                error_log("FCM Purchase Success failed for user ID " . $resolvedOrderRow['subscriber_id'] . ", device $device\n", 3, $errorLog);
	                                            }
	                                        }
	                                    }
	                                } else {
	                                    error_log("No device found for user ID " . $resolvedOrderRow['subscriber_id'], 3, $errorLog);
	                                }
	                                ################################### FIREBASE NOTIFICATION #########################################

	                                file_put_contents($subscriptionUpdateLog, "Inserted one-time purchase: gateway_subscription_id=$originalTransactionId, transaction_id=$transactionId, status=2, end_date=$expiresDateFormatted" . PHP_EOL, FILE_APPEND);
	                            } else {
	                                error_log("Insert failed: " . mysqli_error($mysqli), 3, $errorLog);
	                                file_put_contents($subscriptionUpdateLog, "Insert failed for gateway_subscription_id=$originalTransactionId: " . mysqli_error($mysqli) . PHP_EOL, FILE_APPEND);
	                            }
	                        } else {
	                            file_put_contents($subscriptionUpdateLog, "Skipped one-time insert: order_details missing for order_id=" . ($chkOrderRow['id'] ?? '') . PHP_EOL, FILE_APPEND);
	                        }
	                    }
	                }

            } else {
                error_log("No expired subscription found for gateway_subscription_id=$originalTransactionId", 3, $errorLog);
                file_put_contents($subscriptionUpdateLog, "No expired subscription (status=7) found for gateway_subscription_id=$originalTransactionId" . PHP_EOL, FILE_APPEND);
            }
            mysqli_free_result($result);
        } else {
            error_log("Missing required fields or not a valid RENEWAL: originalTransactionId=$originalTransactionId, expiresDate=$expiresDate, productId=$productId, notificationType=$notificationType, expiresDateValid=" . ($expiresDate > $currentDate ? 'true' : 'false'), 3, $errorLog);
            file_put_contents($subscriptionUpdateLog, "Skipped processing: Invalid RENEWAL or fields for transactionId=$originalTransactionId" . PHP_EOL, FILE_APPEND);
        }

    } catch (Exception $e) {
        error_log("signedTransactionInfo error: " . $e->getMessage(), 3, $errorLog);
        file_put_contents($logDir . 'transaction_jwt_verify.log', "signedTransactionInfo error: " . $e->getMessage() . PHP_EOL, FILE_APPEND);
    }
}


function sql_value(mysqli $mysqli, $value) {
    if ($value === null) {
        return "NULL";
    }

    return "'" . mysqli_real_escape_string($mysqli, (string)$value) . "'";
}


function fetch_single_assoc(mysqli $mysqli, string $sql): ?array {
    $result = mysqli_query($mysqli, $sql);
    if (!$result) {
        return null;
    }

    $row = mysqli_fetch_assoc($result) ?: null;
    mysqli_free_result($result);

    return $row;
}


function fetch_subscription_by_transaction_id(mysqli $mysqli, ?string $transactionId): ?array {
    if (!$transactionId) {
        return null;
    }

    $transactionId = mysqli_real_escape_string($mysqli, $transactionId);

    return fetch_single_assoc(
        $mysqli,
        "SELECT id, order_id, subscriber_id FROM tbl_customer_subscriptions WHERE trans_id='" . $transactionId . "' ORDER BY id DESC LIMIT 1"
    );
}


function fetch_latest_subscription_by_gateway_subscription_id(mysqli $mysqli, ?string $gatewaySubscriptionId): ?array {
    if (!$gatewaySubscriptionId) {
        return null;
    }

    $gatewaySubscriptionId = mysqli_real_escape_string($mysqli, $gatewaySubscriptionId);

    return fetch_single_assoc(
        $mysqli,
        "SELECT id, order_id, subscriber_id, status FROM tbl_customer_subscriptions WHERE gateway_subscription_id='" . $gatewaySubscriptionId . "' ORDER BY created DESC, id DESC LIMIT 1"
    );
}


function fetch_order_context(mysqli $mysqli, int $orderId): array {
    if ($orderId <= 0) {
        return [null, null];
    }

    $orderRow = fetch_single_assoc($mysqli, "SELECT * FROM tbl_order WHERE id=" . $orderId . " LIMIT 1");
    $orderDetailRow = fetch_single_assoc($mysqli, "SELECT * FROM tbl_order_details WHERE order_id=" . $orderId . " ORDER BY id DESC LIMIT 1");

    return [$orderRow, $orderDetailRow];
}


function format_ist_now(): string {
    return (new DateTime('now', new DateTimeZone('Asia/Kolkata')))->format('Y-m-d H:i:s');
}


function build_subscription_insert_sql_from_order(mysqli $mysqli, array $orderRow, array $orderDetailRow, array $context): string {
    $packageTitle = $orderDetailRow['item_name'] ?? ($context['product_id'] ?? '');
    $price = $context['price'] ?? '0.00';
    $basicAmount = $orderDetailRow['item_price'] ?? $orderDetailRow['real_price'] ?? $orderDetailRow['total'] ?? $price;
    $currency = $context['currency'] ?? ($orderDetailRow['currency'] ?? ($orderRow['currency'] ?? 'USD'));
    $currencyId = $orderDetailRow['currency_id'] ?? ($orderRow['currency_id'] ?? 4);
    $trialPeriod = !empty($context['is_free_trial']) ? ($orderDetailRow['period'] ?? 'FREE_TRIAL') : null;
    $trialLength = !empty($context['is_free_trial']) ? ($orderDetailRow['period_interval'] ?? 0) : 0;

    $data = [
        'app_id' => $orderDetailRow['app_id'] ?? ($orderRow['app_id'] ?? 5013),
        'order_id' => $orderRow['id'] ?? ($orderDetailRow['order_id'] ?? 0),
        'trans_id' => $context['transaction_id'] ?? '',
        'pg_ref_id' => $orderDetailRow['pg_ref_id'] ?? ($orderRow['pg_ref_id'] ?? ($context['transaction_id'] ?? '')),
        'device_id' => $orderRow['device_id'] ?? 0,
        'gateway_subscription_id' => $context['gateway_subscription_id'] ?? ($orderRow['gateway_consent_id'] ?? ''),
        'pg_payment_data' => $context['pg_payment_data'] ?? '',
        'channel' => $orderRow['channel'] ?? '',
        'package_id' => $orderDetailRow['item_id'] ?? 0,
        'package_title' => $packageTitle,
        'package_code' => $context['product_id'] ?? '',
        'package_type' => 0,
        'package_mode' => $orderDetailRow['package_mode'] ?? 'OTT',
        'price' => $price,
        'basic_amount' => $basicAmount,
        'tax_amt' => $orderDetailRow['tax_amt'] ?? '0.00',
        'subscriber_id' => $orderRow['subscriber_id'] ?? ($orderDetailRow['subscriber_id'] ?? 0),
        'msisdn' => $orderDetailRow['s_contact_number'] ?? ($orderDetailRow['b_contact_number'] ?? ''),
        'role_type' => $orderRow['role_type'] ?? ($orderDetailRow['role_type'] ?? 1),
        'gateway_type' => $orderDetailRow['gateway_type'] ?? ($orderRow['gateway_type'] ?? 13),
        'pg_name' => $orderDetailRow['pg_name'] ?? ($orderRow['pg_name'] ?? 'apple_inapp_purchase'),
        'region_type' => $orderDetailRow['region_type'] ?? ($orderRow['region_type'] ?? 1),
        'local_user' => $orderDetailRow['local_user'] ?? 0,
        'state_code' => $orderDetailRow['b_state_code'] ?? 0,
        'period' => $orderDetailRow['period'] ?? 'Month',
        'period_interval' => $orderDetailRow['period_interval'] ?? 1,
        'trial_period' => $trialPeriod,
        'trial_length' => $trialLength,
        'subscription_type' => $orderDetailRow['subscription_type'] ?? 0,
        'output_video_limit' => $orderDetailRow['output_video_limit'] ?? 0,
        'additional_cost_per_unit' => $orderDetailRow['additional_cost_per_unit'] ?? 0,
        'no_videos' => 0,
        'no_plays' => 0,
        'status' => 2,
        'platform' => 'webhook',
        'extended_status' => $orderRow['extended_status'] ?? 0,
        'start_date' => $context['purchase_date'] ?? date('Y-m-d H:i:s'),
        'end_date' => $context['expires_date'] ?? date('Y-m-d H:i:s'),
        'autorenew' => 1,
        'currency_id' => $currencyId,
        'currency' => $currency,
        'created' => $context['purchase_date'] ?? date('Y-m-d H:i:s'),
        'is_cancelled' => 0,
        'deactivation_type' => '',
        'recurring' => $context['recurring'] ?? 1,
        'purchase_token' => '',
        'package_name' => $context['product_id'] ?? $packageTitle,
        'purchase_type' => $context['purchase_type'] ?? 'PURCHASED',
    ];

    $columns = implode(", ", array_keys($data));
    $values = [];
    foreach ($data as $value) {
        $values[] = sql_value($mysqli, $value);
    }

    return "INSERT INTO tbl_customer_subscriptions (" . $columns . ") VALUES (" . implode(", ", $values) . ")";
}


function SendPurchaseSuccessFCMNotification($DeviceID, $device) {
    $serviceAccountFile = __DIR__ . '/drama-shorts-abb61-firebase-adminsdk-fbsvc-44b0f0865f.json';

    // Initialize Google Client
    $client = new Client();
    $client->setAuthConfig($serviceAccountFile);
    $client->setScopes(['https://www.googleapis.com/auth/firebase.messaging']);

    // Get access token
    $tokenArray = $client->fetchAccessTokenWithAssertion();
    if (!isset($tokenArray['access_token'])) {
        echo "Failed to get access token\n";
        return false;
    }
    $accessToken = $tokenArray['access_token'];

    // Build message payload
  
    $payloadData = [
        'trigger_type' => 'user',
        'trigger_action' => 'purchase_success'
    ];

    $payloadJSON = json_encode($payloadData);

    // Android / TV
    if ($device === 'mobile' || $device === 'tv') {
        $payload = [
            'message' => [
                'token' => $DeviceID,
                'data' => [
                    'title' => 'Purchase Success',
                    'body'  => $payloadJSON
                ]
            ]
        ];
    } else {
        // iOS / APNS
        $payload = [
            'message' => [
                'token' => $DeviceID,
                'apns' => [
                    'payload' => [
                        'aps' => [
                            'content-available' => true
                        ],
                        'customData' => [
                            'title' => 'Purchase Success',
                            'body'  => $payloadJSON
                        ]
                    ]
                ]
            ]
        ];
    }

    // Get project ID from JSON
    $credentials = json_decode(file_get_contents($serviceAccountFile), true);
    $projectId = $credentials['project_id'];

    // Send FCM via HTTP v1 API
    $ch = curl_init("https://fcm.googleapis.com/v1/projects/$projectId/messages:send");
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $accessToken,
        'Content-Type: application/json'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);

    $response = curl_exec($ch);
    if ($response === false) {
        echo "FCM curl error: " . curl_error($ch);
        curl_close($ch);
        return false;
    }

    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    echo "FCM HTTP Code: $httpCode, Response: $response\n";

    return $httpCode === 200;
}


// Return 200 OK to Apple
http_response_code(200);
echo 'OK';
?>
