<?php

namespace Tests\Unit\Services;

use Tests\TestCase;
use App\Services\MLMCommissionService;
use App\Services\PaymentService;
use App\Models\User;
use App\Models\Order;
use App\Models\Commission;
use App\Models\Wallet;
use App\Models\MlmLevel;

class MLMCommissionServiceTest extends TestCase
{
    /**
     * TEST 1: Direct sale commission créée
     * 
     * SCENARIO:
     * - Seller vend produit 100,000 XOF
     * - Commission rate: 10%
     * 
     * EXPECTED:
     * - Commission creéée avec montant = 10,000 XOF
     * - Type = 'sale'
     * - Status = 'pending'
     */
    public function test_direct_sale_commission_created()
    {
        $seller = factory(User::class)->create(['role' => 'seller']);
        $order = factory(Order::class)->create([
            'seller_id' => $seller->id,
            'total_amount' => 100000
        ]);

        MLMCommissionService::processOrderCommissions($order);

        $commission = Commission::where('order_id', $order->id)
            ->where('type', 'sale')
            ->first();

        $this->assertNotNull($commission);
        $this->assertEquals(10000, $commission->amount); // 10% de 100k
        $this->assertEquals('pending', $commission->status);
    }

    /**
     * TEST 2: MLM chain commissions pour sponsorship
     * 
     * SCENARIO:
     * - User A (member) parrainé par User B
     * - User B parrainé par User C
     * - User A effectue premier achat (100k XOF)
     * 
     * EXPECTED:
     * - Commission Niveau 1 (User B) = 5% = 5,000 XOF
     * - Commission Niveau 2 (User C) = 3% = 3,000 XOF
     * - Status = 'pending'
     */
    public function test_mlm_chain_commissions_created()
    {
        // Setup chain
        $levelC = factory(User::class)->create(['role' => 'member']);
        $levelB = factory(User::class)->create(['role' => 'member', 'sponsor_id' => $levelC->id]);
        $levelA = factory(User::class)->create(['role' => 'member', 'sponsor_id' => $levelB->id]);
        
        // MlmLevels doivent exister
        MlmLevel::create(['level' => 1, 'commission_rate' => 5.00]);
        MlmLevel::create(['level' => 2, 'commission_rate' => 3.00]);
        
        // Order
        $seller = factory(User::class)->create(['role' => 'seller']);
        $order = factory(Order::class)->create([
            'user_id' => $levelA->id,
            'seller_id' => $seller->id,
            'total_amount' => 100000
        ]);

        MLMCommissionService::processOrderCommissions($order);

        // Verify Level 1 commission (User B)
        $comm1 = Commission::where('order_id', $order->id)
            ->where('type', 'level1')
            ->where('user_id', $levelB->id)
            ->first();
        $this->assertNotNull($comm1);
        $this->assertEquals(5000, $comm1->amount); // 5% de 100k

        // Verify Level 2 commission (User C)
        $comm2 = Commission::where('order_id', $order->id)
            ->where('type', 'level2')
            ->where('user_id', $levelC->id)
            ->first();
        $this->assertNotNull($comm2);
        $this->assertEquals(3000, $comm2->amount); // 3% de 100k
    }

    /**
     * TEST 3: Pas de commissions MLM pour achats récurrents
     * 
     * SCENARIO:
     * - User A a déjà effectué un achat (first_purchase_done = true)
     * - User A effectue 2e achat
     * 
     * EXPECTED:
     * - Commission directe seller créée
     * - PAS de commissions MLM
     */
    public function test_no_mlm_commissions_for_repeat_purchases()
    {
        $seller = factory(User::class)->create(['role' => 'seller']);
        $buyer = factory(User::class)->create([
            'role' => 'member',
            'sponsor_id' => factory(User::class)->create()->id,
            'first_purchase_done' => true // Achat précédent effectué
        ]);

        $order = factory(Order::class)->create([
            'user_id' => $buyer->id,
            'seller_id' => $seller->id,
            'total_amount' => 50000
        ]);

        MLMCommissionService::processOrderCommissions($order);

        // Commission directe seller: OK
        $saleComm = Commission::where('order_id', $order->id)->where('type', 'sale')->first();
        $this->assertNotNull($saleComm);

        // Pas de commissions MLM
        $mlmComms = Commission::where('order_id', $order->id)
            ->where('type', 'like', 'level%')
            ->get();
        $this->assertEquals(0, $mlmComms->count());
    }

    /**
     * TEST 4: Protection contre boucles dans arbre MLM
     * 
     * SCENARIO:
     * - User A → User B → User C → User A (BOUCLE!)
     * 
     * EXPECTED:
     * - validateSponsorshipTree retourne false
     */
    public function test_mlm_tree_loop_detection()
    {
        $userA = factory(User::class)->create(['role' => 'member']);
        $userB = factory(User::class)->create(['role' => 'member', 'sponsor_id' => $userA->id]);
        $userC = factory(User::class)->create(['role' => 'member', 'sponsor_id' => $userB->id]);
        
        // Créer la boucle (C → A)
        $userA->update(['sponsor_id' => $userC->id]);

        // Validation doit détecter la boucle
        $isValid = MLMCommissionService::validateSponsorshipTree($userA);
        $this->assertFalse($isValid);
    }

    /**
     * TEST 5: Commission récréditée en portefeuille
     * 
     * SCENARIO:
     * - Commission créée (status = 'pending')
     * - Appeler creditCommission()
     * 
     * EXPECTED:
     * - Commission.status = 'paid'
     * - Wallet.balance augmentée
     * - WalletTransaction créée
     */
    public function test_commission_credited_to_wallet()
    {
        $user = factory(User::class)->create();
        $wallet = factory(Wallet::class)->create(['user_id' => $user->id, 'balance' => 0]);
        
        $commission = Commission::create([
            'user_id' => $user->id,
            'amount' => 5000,
            'status' => 'pending',
            'type' => 'level1'
        ]);

        $balanceBefore = $wallet->fresh()->balance;
        MLMCommissionService::creditCommission($commission);
        $balanceAfter = $wallet->fresh()->balance;

        $this->assertEquals('paid', $commission->fresh()->status);
        $this->assertEquals(5000, $balanceAfter - $balanceBefore);
    }
}

class PaymentServiceTest extends TestCase
{
    /**
     * TEST 1: Webhook signature validation
     * 
     * SCENARIO:
     * - Webhook reçu de Flutterwave
     * - Signature HMAC-SHA256 valide
     * 
     * EXPECTED:
     * - verifyWebhookSignature retourne true
     */
    public function test_webhook_signature_validation_valid()
    {
        $payload = json_encode(['reference' => 'FLW123', 'status' => 'successful']);
        $secret = config('payment.flutterwave.webhook_secret');
        $validSignature = hash_hmac('sha256', $payload, $secret);

        $isValid = PaymentService::verifyWebhookSignature($payload, $validSignature);
        $this->assertTrue($isValid);
    }

    /**
     * TEST 2: Rejection de signature invalide
     * 
     * SCENARIO:
     * - Webhook avec signature incorrecte
     * 
     * EXPECTED:
     * - verifyWebhookSignature retourne false
     */
    public function test_webhook_signature_validation_invalid()
    {
        $payload = json_encode(['reference' => 'FLW123']);
        $invalidSignature = 'wrong_signature_xxx';

        $isValid = PaymentService::verifyWebhookSignature($payload, $invalidSignature);
        $this->assertFalse($isValid);
    }

    /**
     * TEST 3: Transaction idempotency (replay attack prevention)
     * 
     * SCENARIO:
     * - Webhook processé une première fois
     * - Même webhook reçu 2e fois
     * 
     * EXPECTED:
     * - Première fois: Transaction créée, wallet crédité
     * - Deuxième fois: Pas de duplication, montant ajouté qu'une fois
     */
    public function test_webhook_idempotency()
    {
        $user = factory(User::class)->create();
        $wallet = factory(Wallet::class)->create(['user_id' => $user->id, 'balance' => 0]);
        
        $webhookData = [
            'reference' => 'FLW_' . uniqid(),
            'status' => 'successful',
            'amount' => 50000,
            'currency' => 'XOF'
        ];

        // Appel 1
        PaymentService::processFlutterwaveCallback($webhookData);
        $balance1 = $wallet->fresh()->balance;

        // Appel 2 (replay)
        PaymentService::processFlutterwaveCallback($webhookData);
        $balance2 = $wallet->fresh()->balance;

        // Balance devrait augmenter qu'une fois
        $this->assertEquals($balance1, $balance2);
        $this->assertEquals(50000, $balance1);
    }
}

/**
 * RÉSUMÉ DES TESTS
 * 
 * MLM Service Tests:
 * ✓ TEST 1: Commission vente directe
 * ✓ TEST 2: Chaîne MLM (multi-niveaux)
 * ✓ TEST 3: Pas commissions pour achats récurrents
 * ✓ TEST 4: Détection boucles arbre MLM
 * ✓ TEST 5: Crédit commission en portefeuille
 * 
 * Payment Service Tests:
 * ✓ TEST 1: Signature validation (valid)
 * ✓ TEST 2: Signature validation (invalid)
 * ✓ TEST 3: Idempotency (replay attack prevention)
 * 
 * TO RUN TESTS:
 * php artisan test Tests/Unit/Services/MLMCommissionServiceTest
 * php artisan test Tests/Unit/Services/PaymentServiceTest
 * 
 * EXPECTED RESULT: All tests passing ✅
 */
?>
