<?php

/**
 * E2E: send production STK then poll payment + ngrok for callback (max 120s).
 * Usage: php storage/app/e2e_mpesa_stk_test.php
 */

require __DIR__.'/../../vendor/autoload.php';
$app = require __DIR__.'/../../bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();

use App\Models\Payment;
use App\Models\PaymentTransactionLog;
use App\Services\MpesaService;
use App\Services\PlatformSaasBillingService;

$phoneRaw = '0728883160';
$phone = PlatformSaasBillingService::normalizeKenyanMsisdn($phoneRaw);
if (! $phone) {
    echo "FAIL: invalid phone {$phoneRaw}\n";
    exit(1);
}

$isp = App\Models\ISP::query()->orderBy('id')->first();
if (! $isp) {
    echo 'FAIL: no ISP in database\n';
    exit(1);
}

echo "=== M-Pesa E2E test ===\n";
echo 'env='.config('app.env').' mpesa='.config('services.mpesa.environment')."\n";
echo 'callback='.config('services.mpesa.callback_url')."\n";
echo "phone={$phone} isp_id={$isp->id}\n";

$amount = max(1, (int) ceil((float) config('services.mpesa.saas_onboarding_verification_amount', 1)));

$payment = Payment::create([
    'isp_id' => $isp->id,
    'customer_id' => null,
    'invoice_id' => null,
    'payment_method' => 'mpesa',
    'amount' => $amount,
    'phone_number' => $phone,
    'status' => 'pending',
    'metadata' => [
        'purpose' => 'saas_onboarding_verification',
        'e2e_test' => now()->toIso8601String(),
    ],
]);

$mpesa = new MpesaService(null);
$result = $mpesa->initiateStkPush($payment->fresh());

if (! ($result['success'] ?? false)) {
    echo 'FAIL STK initiate: '.json_encode($result)."\n";
    exit(1);
}

$payment->refresh();
$checkoutId = $result['checkout_request_id'] ?? $payment->transaction_id;
echo "STK_SENT payment_id={$payment->id} checkout={$checkoutId}\n";
echo ">>> Approve KES {$amount} on handset {$phoneRaw} now (120s window)...\n";

$deadline = time() + 120;
$lastStatus = 'pending';

while (time() < $deadline) {
    sleep(5);
    $payment->refresh();
    $lastStatus = $payment->status;

    $ngrokHit = false;
    try {
        $ctx = stream_context_create(['http' => ['timeout' => 3]]);
        $raw = @file_get_contents('http://127.0.0.1:4040/api/requests/http', false, $ctx);
        if ($raw) {
            $data = json_decode($raw, true);
            foreach ($data['requests'] ?? [] as $req) {
                $uri = $req['request']['uri'] ?? '';
                if (str_contains($uri, '/api/payments/mpesa/callback')) {
                    $ngrokHit = true;
                    break;
                }
            }
        }
    } catch (Throwable) {
        // ignore
    }

  $isp->refresh();
    $verified = $isp->saas_payment_verified_at ? 'yes' : 'no';

    echo sprintf(
        "[%s] payment_status=%s isp_verified=%s ngrok_callback_seen=%s\n",
        date('H:i:s'),
        $lastStatus,
        $verified,
        $ngrokHit ? 'yes' : 'no'
    );

    if ($lastStatus === 'completed') {
        $log = PaymentTransactionLog::query()
            ->where('payment_id', $payment->id)
            ->where('transaction_type', 'webhook')
            ->where('status', 'completed')
            ->latest()
            ->first();

        echo "SUCCESS: callback processed. processed_at={$payment->processed_at}\n";
        if ($log) {
            echo 'webhook_log_id='.$log->id."\n";
        }
        echo 'isp saas_payment_verified_at='.($isp->saas_payment_verified_at ?? 'null')."\n";
        exit(0);
    }
}

echo "TIMEOUT: payment still {$lastStatus} after 120s.\n";
$failLog = PaymentTransactionLog::query()
    ->where('payment_id', $payment->id)
    ->latest()
    ->first();
if ($failLog) {
    echo 'latest_log: type='.$failLog->transaction_type.' status='.$failLog->status.' err='.($failLog->error_message ?? '')."\n";
}
exit(2);
