<?php
/**
 * webhook/index.php — GoPay Unified Webhook Handler (Payin + Payout)
 * Commission model: L1=15%/6%, L2=6%/3%, L3=2%/2% (first/subsequent deposit)
 * 
 * GoPay sends JSON POST with x-signature header = HMAC-SHA256(raw_body, webhook_secret)
 * Events: payin.success, payout.success, payout.failed
 * Must respond HTTP 200 with body "ok" to acknowledge.
 */
require_once __DIR__ . '/../config.php';

// Force Pakistan Timezone
date_default_timezone_set('Asia/Karachi');
$pdo->exec("SET time_zone = '+05:00';");

$log = __DIR__ . '/gopay_webhook_log.txt';

// Read raw body
$raw_body = file_get_contents('php://input');
$post = json_decode($raw_body, true) ?: [];

file_put_contents($log, date('Y-m-d H:i:s') . " | IN: " . $raw_body . "\n", FILE_APPEND);

if (empty($post)) {
    file_put_contents($log, date('Y-m-d H:i:s') . " | REJECTED: Empty payload\n", FILE_APPEND);
    http_response_code(200);
    echo "ok";
    exit;
}

// ============================================================
// SIGNATURE VERIFICATION
// ============================================================
$stmt = $pdo->query("SELECT setting_value FROM admin_settings WHERE setting_key = 'gopay_webhook_secret'");
$webhook_secret = $stmt->fetchColumn() ?: '';

$provided_signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$expected_signature = hash_hmac('sha256', $raw_body, $webhook_secret);

if (empty($provided_signature) || !hash_equals($expected_signature, $provided_signature)) {
    file_put_contents($log, date('Y-m-d H:i:s') . " | CRITICAL: SIGNATURE MISMATCH! Expected=$expected_signature Got=$provided_signature\n", FILE_APPEND);
    http_response_code(200);
    echo "ok"; // Still respond ok to stop retries, but don't process
    exit;
}

$event = $post['event'] ?? '';

// Determine if this is a payin or payout
$is_payin = ($event === 'payin.success');
$is_payout = (strpos($event, 'payout.') === 0);

// If no event is provided, try to deduce from payload (fallback for new API)
if (empty($event)) {
    if (isset($post['merchant_order_id'])) {
        $is_payin = true;
    } elseif (isset($post['merchant_payout_id'])) {
        $is_payout = true;
    }
}

// ============================================================
// PAYIN SUCCESS — Deposit confirmed
// ============================================================
if ($is_payin) {
    $order_id = $post['merchant_order_id'] ?? '';
    $status   = strtolower($post['status'] ?? '');

    if (empty($order_id) || $status !== 'success') {
        file_put_contents($log, date('Y-m-d H:i:s') . " | PAYIN: Not success or no order_id: $order_id status=$status\n", FILE_APPEND);
        echo "ok"; exit;
    }

    // Find pending deposit
    $st = $pdo->prepare("SELECT * FROM deposits WHERE order_id=? AND status='pending'");
    $st->execute([$order_id]);
    $deposit = $st->fetch();

    if (!$deposit) {
        file_put_contents($log, date('Y-m-d H:i:s') . " | PAYIN: Already processed or not found: $order_id\n", FILE_APPEND);
        echo "ok"; exit;
    }

    $dep_id = (int)$deposit['id'];
    $uid    = (int)$deposit['user_id'];
    $amt    = (float)$deposit['amount'];

    // --- BONUS CALCULATION START ---
    $bonus = 0;
    $bonus_wager = 0;
    $created_at = $deposit['created_at'] ?? date('Y-m-d H:i:s');

    if (strtotime($created_at) >= strtotime('2026-05-15 00:00:00')) {
        $settings_st = $pdo->query("SELECT setting_key, setting_value FROM admin_settings WHERE setting_key IN ('base_deposit_wager_multiplier', 'bonus_wager_multiplier', 'deposit_wager_multiplier', 'deposit_bonus_tiers')");
        $settings = $settings_st->fetchAll(PDO::FETCH_KEY_PAIR);
        
        $base_wager_multiplier = (float)($settings['base_deposit_wager_multiplier'] ?? 1);
        $bonus_wager_multiplier = (float)($settings['bonus_wager_multiplier'] ?? ($settings['deposit_wager_multiplier'] ?? 1));
        $bonus_tiers = json_decode($settings['deposit_bonus_tiers'] ?? '[]', true) ?: [];

        foreach ($bonus_tiers as $tier) {
            if ($amt >= $tier['min']) {
                $bonus = $tier['bonus'];
                break;
            }
        }
        
        $bonus_wager = $bonus * $bonus_wager_multiplier;
        $total_wager = ($amt * $base_wager_multiplier) + $bonus_wager;
    } else {
        $total_wager = $amt;
    }

    $total_credit = $amt + $bonus;
    // --- BONUS CALCULATION END ---

    // Is this the user's first deposit?
    $prev_deps = (int)$pdo->query("SELECT COALESCE(SUM(amount),0) FROM deposits WHERE user_id=$uid AND status='approved'")->fetchColumn();
    $is_first  = ($prev_deps <= 0);

    // Commission rates
    $rates = $is_first
        ? [1 => 0.15, 2 => 0.06, 3 => 0.02]  // First deposit: 15%, 6%, 2%
        : [1 => 0.06, 2 => 0.03, 3 => 0.02]; // Other deposits: 6%, 3%, 2%

    $pdo->beginTransaction();
    try {
        // Mark deposit approved
        $pdo->prepare("UPDATE deposits SET status='approved', updated_at=NOW() WHERE id=?")->execute([$dep_id]);

        // Credit balance + wager + total_deposits (bonus NOT counted in total_deposits)
        $pdo->prepare("UPDATE users SET balance=COALESCE(balance,0)+?, wager=COALESCE(wager,0)+?, total_deposits=COALESCE(total_deposits,0)+? WHERE id=?")
            ->execute([$total_credit, $total_wager, $amt, $uid]);

        // Walk up referral chain (L1 → L2 → L3)
        $depositor = $pdo->prepare("SELECT referedby FROM users WHERE id=?");
        $depositor->execute([$uid]); $depositor = $depositor->fetch();
        $refcode = $depositor['referedby'] ?? null;

        for ($lvl = 1; $lvl <= 3 && $refcode; $lvl++) {
            $ref = $pdo->prepare("SELECT id FROM users WHERE refercode=?");
            $ref->execute([$refcode]); $ref = $ref->fetch();
            if (!$ref) break;

            // Commission is ONLY calculated on the base $amt, not the bonus
            $comm = round($amt * $rates[$lvl], 2);
            
            $pdo->prepare("INSERT INTO referral_commissions (user_id,from_user_id,deposit_id,amount,level,is_first_deposit) VALUES(?,?,?,?,?,?)")
                ->execute([$ref['id'], $uid, $dep_id, $comm, $lvl, $is_first ? 1 : 0]);
                
            $pdo->prepare("UPDATE users SET unclaimed_earnings=COALESCE(unclaimed_earnings,0)+?, total_commission=COALESCE(total_commission,0)+? WHERE id=?")
                ->execute([$comm, $comm, $ref['id']]);

            // Move to next level
            $nxt = $pdo->prepare("SELECT referedby FROM users WHERE id=?");
            $nxt->execute([$ref['id']]); $nxt = $nxt->fetch();
            $refcode = $nxt['referedby'] ?? null;
        }

        $pdo->commit();
        file_put_contents($log, date('Y-m-d H:i:s') . " | PAYIN SUCCESS: dep#$dep_id uid#$uid Base:Rs$amt Bonus:Rs$bonus first_dep=$is_first\n", FILE_APPEND);
    } catch (Exception $e) {
        $pdo->rollBack();
        file_put_contents($log, date('Y-m-d H:i:s') . " | PAYIN ERROR: " . $e->getMessage() . "\n", FILE_APPEND);
    }

    echo "ok";
    exit;
}

// ============================================================
// PAYOUT SUCCESS / FAILED — Withdrawal callback
// ============================================================
if ($is_payout) {
    $payout_order_id = $post['merchant_payout_id'] ?? $post['merchant_order_id'] ?? '';
    $status = strtolower($post['status'] ?? '');

    if (empty($payout_order_id)) {
        file_put_contents($log, date('Y-m-d H:i:s') . " | PAYOUT: No order ID in payload\n", FILE_APPEND);
        echo "ok"; exit;
    }

    $st = $pdo->prepare("SELECT * FROM withdrawals WHERE payout_order_id=?");
    $st->execute([$payout_order_id]);
    $wd = $st->fetch();

    if (!$wd || $wd['payout_status'] !== 'processing') {
        file_put_contents($log, date('Y-m-d H:i:s') . " | PAYOUT: Not found or not processing: $payout_order_id\n", FILE_APPEND);
        echo "ok"; exit;
    }

    $pdo->beginTransaction();
    try {
        if ($status === 'success' || $status === 'paid' || $status === 'completed' || $event === 'payout.success') {
            // Payout success
            $pdo->prepare("UPDATE withdrawals SET payout_status='sent', status='approved', updated_at=NOW() WHERE id=?")->execute([$wd['id']]);
            $pdo->prepare("UPDATE users SET total_withdrawn=COALESCE(total_withdrawn,0)+? WHERE id=?")->execute([$wd['amount'], $wd['user_id']]);
            $pdo->commit();
            file_put_contents($log, date('Y-m-d H:i:s') . " | PAYOUT SUCCESS: WD#{$wd['id']} Rs{$wd['amount']}\n", FILE_APPEND);
        } elseif ($status === 'failed' || $status === 'rejected' || $event === 'payout.failed') {
            // Payout failed — refund balance
            $reason = $post['reason'] ?? $post['msg'] ?? 'Payout failed by GoPay';
            $pdo->prepare("UPDATE withdrawals SET payout_status='failed', status='rejected', reject_reason=?, updated_at=NOW() WHERE id=?")->execute([$reason, $wd['id']]);
            $pdo->prepare("UPDATE users SET balance=COALESCE(balance,0)+? WHERE id=?")->execute([$wd['amount'], $wd['user_id']]);
            $pdo->commit();
            file_put_contents($log, date('Y-m-d H:i:s') . " | PAYOUT FAILED: WD#{$wd['id']}, refunded Rs{$wd['amount']}\n", FILE_APPEND);
        } else {
            $pdo->rollBack();
            file_put_contents($log, date('Y-m-d H:i:s') . " | PAYOUT: Unknown status '$status' for $payout_order_id\n", FILE_APPEND);
        }
    } catch (Exception $e) {
        $pdo->rollBack();
        file_put_contents($log, date('Y-m-d H:i:s') . " | PAYOUT ERROR: " . $e->getMessage() . "\n", FILE_APPEND);
    }

    echo "ok";
    exit;
}

// Unknown event or format
file_put_contents($log, date('Y-m-d H:i:s') . " | UNKNOWN EVENT/PAYLOAD\n", FILE_APPEND);
echo "ok";
