<?php
/**
 * PayNow Webhook Handler
 * 
 * Official PayNow API webhook endpoint for payment status updates
 * Documentation: https://developers.paynow.co.zw/
 * 
 * This endpoint receives payment status updates from PayNow and
 * processes them according to the official API specifications.
 */

require_once '../../includes/payments.php';
require_once '../../includes/notifications.php';
require_once '../../config/payment_security.php';
require_once '../../includes/paynow/PayNowClient.php';

header('Content-Type: application/json');

// Set security headers for webhook endpoints
PaymentSecurity::setSecurityHeaders();

// Get the raw POST data
$rawData = file_get_contents('php://input');
$data = json_decode($rawData, true) ?? [];

// Log the webhook call
$db = getDB();
$stmt = $db->prepare("
    INSERT INTO payment_logs (action, level, message, context, created_at)
    VALUES ('paynow_webhook', 'info', 'Webhook received', ?, NOW())
");
$stmt->execute([json_encode($data)]);

// Get PayNow settings for signature verification
$stmt = $db->prepare("
    SELECT * FROM payment_gateway_settings
    WHERE gateway_name = 'paynow' AND is_active = 1
    ORDER BY gateway_type DESC
    LIMIT 1
");
$stmt->execute();
$settings = $stmt->fetch();

if (!$settings) {
    http_response_code(500);
    echo json_encode(['success' => false, 'error' => 'PayNow not configured']);
    exit;
}

// Validate webhook signature if provided
$signature = $_SERVER['HTTP_X_PAYNOW_SIGNATURE'] ?? '';
if (!empty($signature) && !empty($rawData)) {
    $paynow = new \PayNow\PayNowClient(
        $settings['api_key'],
        $settings['api_secret'],
        $settings['merchant_id'] ?? '',
        ($settings['gateway_type'] !== 'live')
    );
    
    if (!$paynow->verifyWebhookSignature($signature, $rawData)) {
        // Log invalid signature attempt
        $stmt = $db->prepare("
            INSERT INTO payment_logs (action, level, message, context, created_at)
            VALUES ('paynow_webhook_invalid_signature', 'warning', 'Invalid webhook signature', ?, NOW())
        ");
        $stmt->execute([json_encode(['ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'])]);
        
        // For development, allow request but log warning
        if ($settings['gateway_type'] === 'live') {
            http_response_code(401);
            echo json_encode(['success' => false, 'error' => 'Invalid signature']);
            exit;
        }
    }
}

// Validate webhook data
if (empty($data)) {
    // Try to parse as URL-encoded form data (PayNow traditional format)
    parse_str($rawData, $data);
}

if (empty($data) || (!isset($data['reference']) && !isset($data['transaction_id']))) {
    http_response_code(400);
    echo json_encode(['success' => false, 'error' => 'Invalid webhook data']);
    exit;
}

// Extract reference from data
$reference = $data['reference'] ?? $data['transaction_id'] ?? null;
$status = $data['status'] ?? null;
$hash = $data['hash'] ?? null;

// Find transaction by reference number
$stmt = $db->prepare("SELECT * FROM payment_transactions WHERE reference_number = ?");
$stmt->execute([$reference]);
$transaction = $stmt->fetch();

if (!$transaction) {
    // Try finding by transaction_id if reference not found
    if (isset($data['transaction_id'])) {
        $stmt = $db->prepare("SELECT * FROM payment_transactions WHERE transaction_id = ?");
        $stmt->execute([$data['transaction_id']]);
        $transaction = $stmt->fetch();
    }
    
    if (!$transaction) {
        http_response_code(404);
        echo json_encode(['success' => false, 'error' => 'Transaction not found']);
        exit;
    }
}

// Verify hash if provided
if ($hash && $settings['gateway_type'] === 'live') {
    $paynow = new \PayNow\PayNowClient(
        $settings['api_key'],
        $settings['api_secret'],
        $settings['merchant_id'] ?? '',
        false
    );
    
    if (!$paynow->verifyHash($data, $hash)) {
        $stmt = $db->prepare("
            INSERT INTO payment_logs (action, level, message, context, created_at)
            VALUES ('paynow_webhook_hash_mismatch', 'warning', 'Hash verification failed', ?, NOW())
        ");
        $stmt->execute([json_encode(['reference' => $reference])]);
    }
}

// Update transaction status based on Paynow status
$newStatus = 'pending';
$processed = false;
$statusMessage = '';

// Map PayNow status to our status
switch (strtoupper($status)) {
    case 'PAID':
    case 'SUCCESS':
    case 'COMPLETED':
        $newStatus = 'completed';
        $processed = true;
        $statusMessage = 'Payment received successfully';
        break;
    
    case 'CANCELLED':
    case 'ABANDONED':
        $newStatus = 'cancelled';
        $statusMessage = 'Payment was cancelled by user';
        // Send payment failed notification
        sendPaymentNotification('payment_failed', $transaction['transaction_id']);
        break;
    
    case 'FAILED':
    case 'ERROR':
        $newStatus = 'failed';
        $statusMessage = 'Payment failed';
        // Send payment failed notification
        sendPaymentNotification('payment_failed', $transaction['transaction_id']);
        break;
    
    case 'PENDING':
    case 'PROCESSING':
        $newStatus = 'processing';
        $statusMessage = 'Payment is being processed';
        break;
    
    case 'CREATED':
        $newStatus = 'pending';
        $statusMessage = 'Payment initiated';
        break;
    
    default:
        $newStatus = 'pending';
        $statusMessage = 'Unknown status: ' . $status;
        break;
}

// Update transaction
$stmt = $db->prepare("
    UPDATE payment_transactions
    SET status = ?, gateway_response = ?, processed_at = NOW()
    WHERE id = ?
");
$stmt->execute([$newStatus, json_encode($data), $transaction['id']]);

// Log status update
$stmt = $db->prepare("
    INSERT INTO payment_logs (transaction_id, action, level, message, context, created_at)
    VALUES (?, 'webhook_status_update', 'info', ?, ?, NOW())
");
$stmt->execute([
    $transaction['id'],
    $statusMessage,
    json_encode(['new_status' => $newStatus, 'original_status' => $status])
]);

// If payment was successful, process the enrollment
if ($processed && $newStatus === 'completed') {
    try {
        $gateway = new PaymentGateway('paynow', $transaction['gateway_type']);
        $result = $gateway->processSuccessfulPayment($transaction['transaction_id']);

        if ($result['success']) {
            // Log successful processing
            $stmt = $db->prepare("
                INSERT INTO payment_logs (transaction_id, action, level, message, created_at)
                VALUES (?, 'payment_processed', 'info', 'Payment processed successfully', NOW())
            ");
            $stmt->execute([$transaction['id']]);
            
            // Send success notification
            sendPaymentNotification('payment_success', $transaction['transaction_id']);
        } else {
            // Log processing error - mark for retry
            $stmt = $db->prepare("
                INSERT INTO payment_logs (transaction_id, action, level, message, context, created_at)
                VALUES (?, 'payment_processing_failed', 'error', ?, ?, NOW())
            ");
            $stmt->execute([
                $transaction['id'],
                $result['error'] ?? 'Unknown processing error',
                json_encode(['transaction' => $transaction])
            ]);
            
            // Don't mark as failed - keep for retry
            http_response_code(202); // Accepted but needs retry
            echo json_encode([
                'success' => true, 
                'message' => 'Webhook received, payment processing queued for retry',
                'retry_recommended' => true
            ]);
            exit;
        }
    } catch (Exception $e) {
        // Log error
        $stmt = $db->prepare("
            INSERT INTO payment_logs (transaction_id, action, level, message, context, created_at)
            VALUES (?, 'webhook_processing_error', 'error', ?, ?, NOW())
        ");
        $stmt->execute([
            $transaction['id'],
            $e->getMessage(),
            json_encode(['trace' => $e->getTraceAsString()])
        ]);
        
        // Don't mark transaction as failed - keep for manual review/retry
        http_response_code(202);
        echo json_encode([
            'success' => true,
            'message' => 'Webhook received, manual review needed',
            'requires_attention' => true
        ]);
        exit;
    }
}

// Log webhook processing completion
$stmt = $db->prepare("
    INSERT INTO payment_logs (transaction_id, action, level, message, context, created_at)
    VALUES (?, 'webhook_processed', 'info', 'Webhook processed successfully', ?, NOW())
");
$stmt->execute([$transaction['id'], json_encode(['status' => $newStatus, 'processed' => $processed])]);

// Return success response to Paynow
http_response_code(200);
echo json_encode(['success' => true, 'status' => $newStatus]);
