<?php

declare(strict_types=1);

namespace Tests\Feature\Account;

use App\Enums\SellerTier;
use App\Models\SellerProfile;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;

final class SellerOnboardingTest extends TestCase
{
    use RefreshDatabase;

    /**
     * The central marketplace rule: one account is both buyer and seller.
     * Becoming a seller must not require a second registration.
     */
    #[Test]
    public function an_existing_account_becomes_a_seller_without_a_new_account(): void
    {
        $user = User::factory()->create(['name' => 'Asha Rai']);

        $this->actingAs($user)->postJson('/api/v1/account/seller', [])
            ->assertCreated()
            ->assertJsonPath('data.display_name', 'Asha Rai')
            ->assertJsonPath('data.can_list', true);

        $this->assertDatabaseCount('users', 1);
        $this->assertTrue($user->fresh()->isSeller());

        $this->actingAs($user)->getJson('/api/v1/account')
            ->assertOk()
            ->assertJsonPath('data.is_seller', true);
    }

    #[Test]
    public function it_derives_a_handle_from_the_display_name(): void
    {
        $user = User::factory()->create();

        $this->actingAs($user)->postJson('/api/v1/account/seller', [
            'display_name' => 'Himalaya Domains',
        ])->assertCreated()->assertJsonPath('data.handle', 'himalaya-domains');
    }

    #[Test]
    public function it_avoids_colliding_with_an_existing_handle(): void
    {
        SellerProfile::factory()->create(['handle' => 'himalaya-domains']);

        $user = User::factory()->create();

        $response = $this->actingAs($user)->postJson('/api/v1/account/seller', [
            'display_name' => 'Himalaya Domains',
        ])->assertCreated();

        $handle = $response->json('data.handle');

        $this->assertNotSame('himalaya-domains', $handle);
        $this->assertStringStartsWith('himalaya-domains-', $handle);
    }

    #[Test]
    public function it_rejects_a_handle_already_taken(): void
    {
        SellerProfile::factory()->create(['handle' => 'taken-handle']);

        $this->actingAs(User::factory()->create())
            ->postJson('/api/v1/account/seller', ['handle' => 'taken-handle'])
            ->assertUnprocessable()
            ->assertJsonValidationErrors('handle');
    }

    #[Test]
    public function it_rejects_a_malformed_handle(): void
    {
        $this->actingAs(User::factory()->create())
            ->postJson('/api/v1/account/seller', ['handle' => 'Not A Handle!'])
            ->assertUnprocessable()
            ->assertJsonValidationErrors('handle');
    }

    /**
     * Selling creates an obligation to a buyer, so the account must have proved
     * it can receive mail before it can take that on.
     */
    #[Test]
    public function an_unverified_email_cannot_set_up_selling(): void
    {
        $user = User::factory()->unverified()->create();

        $this->actingAs($user)->postJson('/api/v1/account/seller', [])
            ->assertForbidden();

        $this->assertDatabaseCount('seller_profiles', 0);
    }

    #[Test]
    public function setting_up_selling_twice_is_idempotent(): void
    {
        $user = User::factory()->create();

        $this->actingAs($user)->postJson('/api/v1/account/seller', [])->assertCreated();
        $this->actingAs($user)->postJson('/api/v1/account/seller', [])->assertOk();

        $this->assertDatabaseCount('seller_profiles', 1);
    }

    #[Test]
    public function it_updates_the_seller_profile(): void
    {
        $user = User::factory()->create();
        SellerProfile::factory()->create(['user_id' => $user->getKey()]);

        $this->actingAs($user)->patchJson('/api/v1/account/seller', [
            'display_name' => 'Everest Domains',
            'about' => 'Curated premium names.',
        ])->assertOk()->assertJsonPath('data.display_name', 'Everest Domains');
    }

    #[Test]
    public function a_handle_change_is_audited(): void
    {
        $user = User::factory()->create();
        SellerProfile::factory()->create([
            'user_id' => $user->getKey(),
            'handle' => 'old-handle',
        ]);

        $this->actingAs($user)->patchJson('/api/v1/account/seller', [
            'handle' => 'new-handle',
        ])->assertOk();

        $this->assertDatabaseHas('audit_logs', ['event' => 'seller.profile_updated']);
        $this->assertDatabaseHas('seller_profiles', ['handle' => 'new-handle']);
    }

    #[Test]
    public function requesting_a_seller_profile_that_does_not_exist_returns_not_found(): void
    {
        $this->actingAs(User::factory()->create())
            ->getJson('/api/v1/account/seller')
            ->assertNotFound();
    }

    /**
     * Section 28: internal risk signals must never reach a normal user, and
     * that includes the seller the signal is about.
     */
    #[Test]
    public function the_seller_response_never_exposes_risk_state(): void
    {
        $user = User::factory()->create();
        SellerProfile::factory()->blocked()->create([
            'user_id' => $user->getKey(),
            'risk_score' => 91,
            'listing_suspension_reason' => 'Internal note about suspected fraud.',
        ]);

        $response = $this->actingAs($user)->getJson('/api/v1/account/seller')->assertOk();
        $body = $response->getContent();

        $this->assertStringNotContainsString('risk_level', $body);
        $this->assertStringNotContainsString('risk_score', $body);
        $this->assertStringNotContainsString('blocked', $body);
        $this->assertStringNotContainsString('suspected fraud', $body);

        // The seller is still told, plainly, that they cannot list.
        $response->assertJsonPath('data.can_list', false);
    }

    #[Test]
    public function tier_reflects_verification_and_trading_history(): void
    {
        $standard = SellerProfile::factory()->create();
        $verified = SellerProfile::factory()->identityVerified()->create();
        $pro = SellerProfile::factory()->pro()->create();
        $enterprise = SellerProfile::factory()->enterprise()->create();

        $this->assertSame(SellerTier::Standard, $standard->tier());
        $this->assertSame(SellerTier::Verified, $verified->tier());
        $this->assertSame(SellerTier::Pro, $pro->tier());
        $this->assertSame(SellerTier::Enterprise, $enterprise->tier());
    }

    #[Test]
    public function a_suspended_seller_cannot_list(): void
    {
        $this->assertFalse(SellerProfile::factory()->listingSuspended()->create()->canList());
        $this->assertFalse(SellerProfile::factory()->blocked()->create()->canList());
        $this->assertTrue(SellerProfile::factory()->create()->canList());
    }
}
