<?php

namespace Tests\Feature;

use App\Models\Package;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Paddle\PaddleCheckoutService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use Tests\TestCase;

class PurchaseTest extends TestCase
{
    use RefreshDatabase;

    protected function tearDown(): void
    {
        Mockery::close();
        parent::tearDown();
    }

    public function test_create_paddle_checkout_requires_paddle_price(): void
    {
        [$tenant, $package] = $this->seedTenantWithPackage(includePaddlePrice: false);
        $this->actingAs($tenant->user);

        $response = $this->postJson('/paddle/create-checkout', [
            'package_id' => $package->id,
            'accepted_terms' => true,
        ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors('package_id');
    }

    public function test_create_paddle_checkout_returns_checkout_url(): void
    {
        [$tenant, $package] = $this->seedTenantWithPackage(includePaddlePrice: true);
        $this->actingAs($tenant->user);

        $service = Mockery::mock(PaddleCheckoutService::class);
        $service->shouldReceive('createCheckout')
            ->once()
            ->with(
                Mockery::on(fn ($arg) => $arg instanceof Tenant && $arg->is($tenant)),
                Mockery::on(fn ($arg) => $arg instanceof Package && $arg->is($package)),
                Mockery::on(function ($options) {
                    return ($options['success_url'] ?? null) === null
                        && ($options['return_url'] ?? null) === null
                        && isset($options['metadata']['checkout_session_id']);
                })
            )
            ->andReturn([
                'checkout_url' => 'https://paddle.test/checkout/abc',
            ]);

        $this->app->instance(PaddleCheckoutService::class, $service);

        $response = $this->postJson('/paddle/create-checkout', [
            'package_id' => $package->id,
            'accepted_terms' => true,
        ]);

        $response->assertOk()
            ->assertJson([
                'checkout_url' => 'https://paddle.test/checkout/abc',
            ]);
    }

    public function test_create_paddle_checkout_inline_returns_items(): void
    {
        [$tenant, $package] = $this->seedTenantWithPackage(includePaddlePrice: true);
        $this->actingAs($tenant->user);

        $service = Mockery::mock(PaddleCheckoutService::class);
        $service->shouldNotReceive('createCheckout');
        $this->app->instance(PaddleCheckoutService::class, $service);

        $response = $this->postJson('/paddle/create-checkout', [
            'package_id' => $package->id,
            'inline' => true,
            'accepted_terms' => true,
        ]);

        $response->assertOk()
            ->assertJson([
                'mode' => 'inline',
            ])
            ->assertJsonStructure([
                'mode',
                'items' => [
                    ['priceId', 'quantity'],
                ],
                'custom_data' => ['tenant_id', 'package_id', 'checkout_session_id'],
            ]);

        $payload = $response->json();
        $this->assertSame($package->paddle_price_id, $payload['items'][0]['priceId']);
        $this->assertSame(1, $payload['items'][0]['quantity']);
    }

    private function seedTenantWithPackage(int $price = 10, string $type = 'endcustomer', bool $includePaddlePrice = true): array
    {
        $user = User::factory()->create(['email_verified_at' => now()]);
        $tenant = Tenant::factory()->create(['user_id' => $user->id]);

        $user->forceFill(['tenant_id' => $tenant->id])->save();

        $package = Package::factory()->create([
            'price' => $price,
            'type' => $type,
            'paddle_price_id' => $includePaddlePrice ? 'price_123' : null,
        ]);

        return [$tenant, $package];
    }
}
