<?php

use Illuminate\Database\QueryException;
use Modules\Booking\Models\Booking;
use Modules\Payment\Enums\PaymentMethod;
use Modules\Payment\Enums\PaymentStatus;
use Modules\Payment\Enums\RefundStatus;
use Modules\Payment\Models\Payment;
use Modules\Payment\Models\Refund;

test('a payment belongs to a booking', function () {
    $booking = Booking::factory()->create();

    $payment = Payment::factory()->create(['booking_id' => $booking->id]);

    expect($payment->booking)->toBeInstanceOf(Booking::class)
        ->and($payment->booking->is($booking))->toBeTrue()
        ->and($booking->payments->first()->is($payment))->toBeTrue();
});

test('a booking can have more than one payment attempt', function () {
    $booking = Booking::factory()->create();

    Payment::factory()->failed()->create(['booking_id' => $booking->id]);
    Payment::factory()->completed()->create(['booking_id' => $booking->id]);

    expect($booking->payments)->toHaveCount(2);
});

test('gateway and status cast to their enums', function () {
    $payment = Payment::factory()->create([
        'gateway' => PaymentMethod::KbzMiniApp,
        'status' => PaymentStatus::Completed,
    ]);

    expect($payment->gateway)->toBe(PaymentMethod::KbzMiniApp)
        ->and($payment->status)->toBe(PaymentStatus::Completed);
});

test('a payment defaults to pending', function () {
    $payment = Payment::factory()->create();

    expect($payment->status)->toBe(PaymentStatus::Pending);
});

test('a refund belongs to a payment, not the booking directly', function () {
    $payment = Payment::factory()->completed()->create();

    $refund = Refund::factory()->create(['payment_id' => $payment->id]);

    expect($refund->payment)->toBeInstanceOf(Payment::class)
        ->and($refund->payment->is($payment))->toBeTrue()
        ->and($payment->refunds->first()->is($refund))->toBeTrue();
});

test('a payment can have more than one refund for partial refunds', function () {
    $payment = Payment::factory()->completed()->create(['amount' => 20000]);

    Refund::factory()->completed()->create(['payment_id' => $payment->id, 'amount' => 8000]);
    Refund::factory()->create(['payment_id' => $payment->id, 'amount' => 12000]);

    expect($payment->refunds)->toHaveCount(2);
});

test('refund status casts to its enum and defaults to pending', function () {
    $refund = Refund::factory()->create();

    expect($refund->status)->toBe(RefundStatus::Pending);
});

test('deleting a payment cascades to its refunds', function () {
    $payment = Payment::factory()->completed()->create();
    $refund = Refund::factory()->create(['payment_id' => $payment->id]);

    $payment->delete();

    expect(Refund::find($refund->id))->toBeNull();
});

test('gateway_transaction_id cannot be shared across unrelated retried attempts without being unique-constrained', function () {
    // gateway_transaction_id is not unique-constrained since a failed attempt
    // may legitimately be retried under a fresh Payment row with its own id;
    // this just documents the column accepts duplicates without throwing.
    Payment::factory()->create(['gateway_transaction_id' => 'kbz-txn-1']);

    expect(fn () => Payment::factory()->create(['gateway_transaction_id' => 'kbz-txn-1']))
        ->not->toThrow(QueryException::class);
});
