<?php

namespace Tests\Feature;

use App\Models\CashbackLedger;
use App\Models\CashbackWallet;
use App\Models\Category;
use App\Models\Network;
use App\Models\Plan;
use App\Models\PlanVendorMapping;
use App\Models\User;
use App\Models\Vendor;
use App\Models\Wallet;
use App\Services\Providers\Contracts\ProviderInterface;
use App\Services\Providers\ProviderFactory;
use App\Services\Providers\ProviderResponse;
use App\Services\TransactionService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use Tests\TestCase;

class CashbackSplitPurchaseTest extends TestCase
{
    use RefreshDatabase;

    public function test_purchase_uses_cashback_first_then_wallet_when_enabled(): void
    {
        [$user, $plan] = $this->seedPurchaseData();

        Wallet::create(['user_id' => $user->id, 'balance' => 300]);
        CashbackWallet::create(['user_id' => $user->id, 'balance' => 100]);

        $providerFactory = Mockery::mock(ProviderFactory::class);
        $providerFactory->shouldReceive('forVendor')->andReturn(new class implements ProviderInterface {
            public function getBalance(?\App\Models\Transaction $transaction = null): array { return ['success' => true]; }
            public function getPlans(?\App\Models\Transaction $transaction = null): array { return []; }
            public function purchaseData(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse
            {
                return ProviderResponse::success(
                    message: 'Delivered',
                    vendorReference: 'VREF-SPLIT-001',
                    vendorCost: 250,
                    raw: ['status' => 'success']
                );
            }
            public function purchaseAirtime(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
            public function purchaseCable(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
            public function validateIuc(array $payload, ?\App\Models\Transaction $transaction = null): array { return []; }
            public function purchaseElectricity(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
            public function validateMeter(array $payload, ?\App\Models\Transaction $transaction = null): array { return []; }
            public function purchaseEpin(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
            public function queryTransaction(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
        });
        $this->app->instance(ProviderFactory::class, $providerFactory);

        /** @var TransactionService $transactionService */
        $transactionService = $this->app->make(TransactionService::class);

        $tx = $transactionService->purchase($user, [
            'category_slug' => 'data_sme',
            'plan_id' => $plan->id,
            'phone' => '08030000000',
            'mobile_number' => '08030000000',
            'use_cashback' => true,
            'internal_reference' => 'TX-SPLIT-SUCCESS-001',
        ]);

        $this->assertSame('success', $tx->status);
        $this->assertSame('200.00', (string) $tx->wallet_debit_amount);
        $this->assertSame('100.00', (string) $tx->cashback_debit_amount);
        $this->assertSame('100.00', (string) $user->fresh()->wallet->balance);
        $this->assertSame('0.00', (string) $user->fresh()->cashbackWallet->balance);
        $this->assertDatabaseHas('wallet_ledgers', [
            'reference' => 'wallet:purchase:TX-SPLIT-SUCCESS-001',
            'entry_type' => 'debit',
            'amount' => '200.00',
        ]);
        $this->assertDatabaseHas('cashback_ledgers', [
            'reference' => 'cashback:purchase:TX-SPLIT-SUCCESS-001',
            'entry_type' => 'debit',
            'amount' => '100.00',
        ]);
    }

    public function test_failed_purchase_refunds_wallet_and_cashback_split_once(): void
    {
        [$user, $plan] = $this->seedPurchaseData('VREF-FAIL-001');

        Wallet::create(['user_id' => $user->id, 'balance' => 300]);
        CashbackWallet::create(['user_id' => $user->id, 'balance' => 100]);

        $providerFactory = Mockery::mock(ProviderFactory::class);
        $providerFactory->shouldReceive('forVendor')->andReturn(new class implements ProviderInterface {
            public function getBalance(?\App\Models\Transaction $transaction = null): array { return ['success' => true]; }
            public function getPlans(?\App\Models\Transaction $transaction = null): array { return []; }
            public function purchaseData(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse
            {
                return ProviderResponse::failed('Vendor failed', ['status' => 'failed'], hardFailure: false);
            }
            public function purchaseAirtime(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
            public function purchaseCable(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
            public function validateIuc(array $payload, ?\App\Models\Transaction $transaction = null): array { return []; }
            public function purchaseElectricity(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
            public function validateMeter(array $payload, ?\App\Models\Transaction $transaction = null): array { return []; }
            public function purchaseEpin(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
            public function queryTransaction(array $payload, ?\App\Models\Transaction $transaction = null): ProviderResponse { return ProviderResponse::failed('Not used'); }
        });
        $this->app->instance(ProviderFactory::class, $providerFactory);

        /** @var TransactionService $transactionService */
        $transactionService = $this->app->make(TransactionService::class);

        $tx = $transactionService->purchase($user, [
            'category_slug' => 'data_sme',
            'plan_id' => $plan->id,
            'phone' => '08030000000',
            'mobile_number' => '08030000000',
            'use_cashback' => true,
            'internal_reference' => 'TX-SPLIT-FAIL-001',
        ]);

        $this->assertSame('reversed', $tx->status);
        $this->assertSame('300.00', (string) $user->fresh()->wallet->balance);
        $this->assertSame('100.00', (string) $user->fresh()->cashbackWallet->balance);

        $this->assertDatabaseHas('wallet_ledgers', [
            'reference' => 'wallet:refund:TX-SPLIT-FAIL-001',
            'entry_type' => 'credit',
            'amount' => '200.00',
        ]);
        $this->assertDatabaseHas('cashback_ledgers', [
            'reference' => 'cashback:refund:TX-SPLIT-FAIL-001',
            'entry_type' => 'credit',
            'amount' => '100.00',
        ]);
        $this->assertSame(1, CashbackLedger::query()->where('reference', 'cashback:refund:TX-SPLIT-FAIL-001')->count());
    }

    /**
     * @return array{0: User, 1: Plan}
     */
    protected function seedPurchaseData(string $vendorName = 'Split Vendor'): array
    {
        $user = User::factory()->create();

        $category = Category::create(['name' => 'Data SME', 'slug' => 'data_sme']);
        $network = Network::create([
            'name' => 'MTN',
            'slug' => 'mtn',
            'vendor_network_code_json' => ['msorg' => ['data' => '1']],
        ]);
        $plan = Plan::create([
            'network_id' => $network->id,
            'category_id' => $category->id,
            'name' => 'MTN SME 1GB',
            'value' => '1GB',
            'selling_price' => 300,
            'status' => 'available',
            'sort_order' => 1,
        ]);
        $vendor = Vendor::create([
            'name' => $vendorName,
            'type' => 'msorg',
            'base_url' => 'https://vendor.example.com',
            'auth_type' => 'token',
            'secret_encrypted' => 'abc123',
            'status' => 'active',
            'timeout_seconds' => 30,
        ]);
        PlanVendorMapping::create([
            'plan_id' => $plan->id,
            'vendor_id' => $vendor->id,
            'vendor_plan_code' => 'MTN-SME-1GB',
            'priority' => 1,
            'status' => 'active',
        ]);

        return [$user, $plan];
    }
}
