<?php

namespace Tests\Feature;

use App\Http\Middleware\EnsurePlatformSession;
use App\Models\Bill;
use App\Models\Branch;
use App\Models\Consultation;
use App\Models\Member;
use App\Models\Organization;
use App\Models\Patient;
use App\Models\Payment;
use App\Models\PaymentGatewaySetting;
use App\Models\User;
use App\Models\Visit;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

class CarePaymentGatewayTest extends TestCase
{
    use RefreshDatabase;

    protected User $user;

    protected Organization $organization;

    protected Visit $visit;

    protected Bill $bill;

    protected function setUp(): void
    {
        parent::setUp();
        $this->withoutMiddleware(EnsurePlatformSession::class);

        $this->user = User::create([
            'public_id' => 'test-user-gateway',
            'name' => 'Gateway Admin',
            'email' => 'gateway@example.com',
        ]);

        $this->organization = Organization::create([
            'owner_ref' => $this->user->public_id,
            'name' => 'Gateway Clinic',
            'slug' => 'gateway-clinic',
            'timezone' => 'UTC',
            'settings' => ['onboarded' => true, 'plan' => 'pro', 'plan_expires_at' => now()->addMonth()->toIso8601String()],
        ]);

        Member::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'user_ref' => $this->user->public_id,
            'role' => 'hospital_admin',
        ]);

        $branch = Branch::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'name' => 'Main',
            'is_active' => true,
        ]);

        $patient = Patient::create([
            'uuid' => (string) \Illuminate\Support\Str::uuid(),
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $branch->id,
            'patient_number' => 'LC-2026-00099',
            'first_name' => 'Ama',
            'last_name' => 'Mensah',
            'email' => 'ama@example.com',
        ]);

        $this->visit = Visit::create([
            'uuid' => (string) \Illuminate\Support\Str::uuid(),
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $branch->id,
            'patient_id' => $patient->id,
            'status' => Visit::STATUS_IN_PROGRESS,
            'checked_in_at' => now(),
        ]);

        Consultation::create([
            'uuid' => (string) \Illuminate\Support\Str::uuid(),
            'owner_ref' => $this->user->public_id,
            'visit_id' => $this->visit->id,
            'patient_id' => $patient->id,
            'status' => Consultation::STATUS_COMPLETED,
            'started_at' => now()->subHour(),
            'completed_at' => now(),
        ]);

        $this->actingAs($this->user)
            ->post(route('care.bills.generate', $this->visit));

        $this->bill = Bill::firstOrFail();
    }

    public function test_admin_can_save_paystack_gateway(): void
    {
        $this->actingAs($this->user)
            ->post(route('care.integrations.gateway.save'), [
                'gateway_provider' => 'paystack',
                'gateway_public_key' => 'pk_test_care',
                'gateway_secret_key' => 'sk_test_care',
                'gateway_is_active' => '1',
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('care_payment_gateway_settings', [
            'organization_id' => $this->organization->id,
            'provider' => 'paystack',
            'is_active' => 1,
        ]);

        $setting = PaymentGatewaySetting::query()->where('organization_id', $this->organization->id)->first();
        $this->assertNotNull($setting);
        $this->assertTrue($setting->isConfigured());
        $this->assertSame('sk_test_care', $setting->secret_key);
    }

    public function test_free_plan_cannot_save_gateway(): void
    {
        $this->organization->update([
            'settings' => ['onboarded' => true, 'plan' => 'free'],
        ]);

        $this->actingAs($this->user)
            ->post(route('care.integrations.gateway.save'), [
                'gateway_provider' => 'paystack',
                'gateway_secret_key' => 'sk_test',
                'gateway_is_active' => '1',
            ])
            ->assertRedirect()
            ->assertSessionHas('error');

        $this->assertDatabaseMissing('care_payment_gateway_settings', [
            'organization_id' => $this->organization->id,
        ]);
    }

    public function test_gateway_checkout_and_callback_records_payment(): void
    {
        PaymentGatewaySetting::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'provider' => PaymentGatewaySetting::PROVIDER_PAYSTACK,
            'public_key' => 'pk_test',
            'secret_key' => 'sk_test',
            'is_active' => true,
        ]);

        Http::fake([
            'https://api.paystack.co/transaction/initialize' => Http::response([
                'status' => true,
                'data' => [
                    'authorization_url' => 'https://checkout.paystack.com/care-test',
                    'reference' => 'CARE-TEST-REF-001',
                ],
            ], 200),
            'https://api.paystack.co/transaction/verify/*' => Http::response([
                'status' => true,
                'data' => [
                    'status' => 'success',
                    'amount' => $this->bill->balance_minor,
                    'reference' => 'CARE-TEST-REF-001',
                ],
            ], 200),
        ]);

        $balance = $this->bill->balance_minor;

        $this->actingAs($this->user)
            ->post(route('care.bills.payments.gateway', $this->bill), [
                'amount' => $balance / 100,
            ])
            ->assertRedirect('https://checkout.paystack.com/care-test');

        $pending = Payment::query()->where('bill_id', $this->bill->id)->first();
        $this->assertNotNull($pending);
        $this->assertSame(Payment::STATUS_PENDING, $pending->status);
        $this->assertSame(Payment::METHOD_GATEWAY, $pending->method);
        $this->assertSame('CARE-TEST-REF-001', $pending->reference);

        // Pending must not reduce balance.
        $this->bill->refresh();
        $this->assertSame($balance, $this->bill->balance_minor);

        $this->actingAs($this->user)
            ->get(route('care.bills.payments.callback', ['reference' => 'CARE-TEST-REF-001']))
            ->assertOk();

        $pending->refresh();
        $this->assertSame(Payment::STATUS_PAID, $pending->status);

        $this->bill->refresh();
        $this->assertSame(Bill::STATUS_PAID, $this->bill->status);
        $this->assertSame(0, $this->bill->balance_minor);

        Http::assertSent(fn ($request) => str_contains($request->url(), 'paystack.co/transaction/initialize')
            && $request->hasHeader('Authorization', 'Bearer sk_test'));
    }

    public function test_flutterwave_initialize_uses_major_units(): void
    {
        PaymentGatewaySetting::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'provider' => PaymentGatewaySetting::PROVIDER_FLUTTERWAVE,
            'public_key' => 'FLWPUBK_TEST',
            'secret_key' => 'FLWSECK_TEST',
            'is_active' => true,
        ]);

        Http::fake([
            'https://api.flutterwave.com/v3/payments' => Http::response([
                'status' => 'success',
                'data' => ['link' => 'https://checkout.flutterwave.com/v3/hosted/pay/test'],
            ], 200),
        ]);

        $this->actingAs($this->user)
            ->post(route('care.bills.payments.gateway', $this->bill), [
                'amount' => 50.00,
            ])
            ->assertRedirect('https://checkout.flutterwave.com/v3/hosted/pay/test');

        Http::assertSent(function ($request) {
            if (! str_contains($request->url(), 'flutterwave.com')) {
                return false;
            }
            $data = $request->data();

            return (float) ($data['amount'] ?? 0) === 50.0
                && $request->hasHeader('Authorization', 'Bearer FLWSECK_TEST');
        });
    }

    public function test_hubtel_initialize_uses_basic_auth(): void
    {
        PaymentGatewaySetting::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'provider' => PaymentGatewaySetting::PROVIDER_HUBTEL,
            'public_key' => '201XXXX',
            'secret_key' => 'hubtel-secret',
            'is_active' => true,
        ]);

        Http::fake([
            'https://payproxyapi.hubtel.com/items/initiate' => Http::response([
                'data' => ['checkoutUrl' => 'https://pay.hubtel.com/checkout/test'],
            ], 200),
        ]);

        $this->actingAs($this->user)
            ->post(route('care.bills.payments.gateway', $this->bill), [
                'amount' => 25.00,
            ])
            ->assertRedirect('https://pay.hubtel.com/checkout/test');

        Http::assertSent(function ($request) {
            return str_contains($request->url(), 'hubtel.com')
                && ($request->data()['merchantAccountNumber'] ?? null) === '201XXXX'
                && (float) ($request->data()['totalAmount'] ?? 0) === 25.0;
        });
    }
}
