<?php

namespace Tests\Feature;

use App\Domain\Subscription\PaymentApprovalService;
use App\Enums\PaymentProofStatus;
use App\Models\Plan;
use App\Models\SubscriptionPayment;
use App\Models\Tenant;
use App\Models\User;
use App\Support\Tenancy;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PaymentApprovalTest extends TestCase
{
    use RefreshDatabase;

    protected Tenant $tenant;
    protected SubscriptionPayment $payment;
    protected int $reviewerId;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();

        $this->tenant = Tenant::create(['name' => 'C', 'slug' => 'c', 'status' => 'grace']);
        $plan = Plan::first();
        $this->tenant->subscription()->create([
            'plan_id' => $plan->id, 'status' => 'grace',
            'starts_at' => now()->subMonth(), 'current_period_ends_at' => now()->subDay(),
            'grace_ends_at' => now()->addDays(5),
        ]);

        app(Tenancy::class)->set($this->tenant);
        $this->payment = SubscriptionPayment::create([
            'tenant_id' => $this->tenant->id, 'plan_id' => $plan->id,
            'gateway' => 'zaincash', 'amount' => $plan->price_monthly_iqd,
            'currency' => 'IQD', 'status' => 'pending', 'period_months' => 1,
            'proof_reference' => 'ZC-99',
        ]);

        $reviewer = User::withoutEvents(fn () => User::create([
            'tenant_id' => null, 'name' => 'Admin', 'email' => 'a@medibookai.com', 'password' => 'password123',
        ]));
        $reviewer->assignRole('super_admin');
        $this->reviewerId = $reviewer->id;
    }

    public function test_submit_logs_audit_entry(): void
    {
        app(PaymentApprovalService::class)->submitted($this->payment, '1.2.3.4');

        $this->assertDatabaseHas('payment_proof_reviews', [
            'subscription_payment_id' => $this->payment->id,
            'action' => 'submitted', 'to_status' => 'pending', 'ip' => '1.2.3.4',
        ]);
    }

    public function test_approve_activates_subscription_and_logs(): void
    {
        app(PaymentApprovalService::class)->approve($this->payment, $this->reviewerId, 'Verified', '9.9.9.9');

        $this->assertSame(PaymentProofStatus::Approved, $this->payment->fresh()->status);
        $this->assertSame('active', $this->tenant->fresh()->status);
        $this->assertSame('active', $this->tenant->subscription->fresh()->status);
        $this->assertDatabaseHas('payment_proof_reviews', [
            'subscription_payment_id' => $this->payment->id,
            'action' => 'approved', 'from_status' => 'pending', 'to_status' => 'approved',
            'reviewer_id' => $this->reviewerId, 'note' => 'Verified',
        ]);
        // covers_from / covers_until stamped
        $this->assertNotNull($this->payment->fresh()->covers_until);
    }

    public function test_reject_logs_and_does_not_activate(): void
    {
        app(PaymentApprovalService::class)->reject($this->payment, $this->reviewerId, 'Blurry receipt', '8.8.8.8');

        $this->assertSame(PaymentProofStatus::Rejected, $this->payment->fresh()->status);
        $this->assertSame('grace', $this->tenant->subscription->fresh()->status);
        $this->assertDatabaseHas('payment_proof_reviews', [
            'action' => 'rejected', 'note' => 'Blurry receipt',
        ]);
    }

    public function test_request_info_logs(): void
    {
        app(PaymentApprovalService::class)->requestInfo($this->payment, $this->reviewerId, 'Send full screenshot');

        $this->assertSame(PaymentProofStatus::InfoRequested, $this->payment->fresh()->status);
        $this->assertDatabaseHas('payment_proof_reviews', ['action' => 'info_requested']);
    }

    public function test_double_approve_is_blocked(): void
    {
        $svc = app(PaymentApprovalService::class);
        $svc->approve($this->payment, $this->reviewerId);

        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
        $svc->approve($this->payment->fresh(), $this->reviewerId);
    }

    public function test_super_admin_endpoint_approves(): void
    {
        $reviewer = User::find($this->reviewerId);
        app(Tenancy::class)->forget();

        $this->actingAs($reviewer)
            ->post('http://'.config('tenancy.central_domain').'/admin/payments/'.$this->payment->id.'/review', [
                'action' => 'approve',
            ])->assertRedirect();

        $this->assertSame(PaymentProofStatus::Approved, $this->payment->fresh()->status);
    }

    public function test_reject_requires_note_via_endpoint(): void
    {
        $reviewer = User::find($this->reviewerId);
        app(Tenancy::class)->forget();

        $this->actingAs($reviewer)
            ->post('http://'.config('tenancy.central_domain').'/admin/payments/'.$this->payment->id.'/review', [
                'action' => 'reject',
            ])->assertSessionHasErrors('note');
    }
}
