<?php

namespace Tests\Feature\Auth;

use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Auth\Models\ResetPasswordAttempt;
use App\Domains\Auth\Models\User;
use App\Domains\Notification\Events\PasswordResetRequested;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event;
use Tests\TestCase;

class CreateResetPasswordAttemptControllerTest extends TestCase
{
    use RefreshDatabase;

    private Tenant $tenant;

    protected function setUp(): void
    {
        parent::setUp();

        Event::fake([PasswordResetRequested::class]);

        $header = Attachment::query()->create([
            'path' => 'test/reset-header.png',
            'filename' => 'header.png',
            'type' => AttachmentType::Image,
            'mime_type' => 'image/png',
        ]);
        $footer = Attachment::query()->create([
            'path' => 'test/reset-footer.png',
            'filename' => 'footer.png',
            'type' => AttachmentType::Image,
            'mime_type' => 'image/png',
        ]);
        $this->tenant = Tenant::query()->create([
            'codigo' => 'reset-tenant',
            'nombre' => 'Reset Tenant',
            'dominio' => 'reset.local',
            'primary_color' => '#112233',
            'secondary_color' => '#000000',
            'danger_color' => '#000000',
            'success_color' => '#000000',
            'header_bg_color' => '#000000',
            'footer_bg_color' => '#000000',
            'header_logo_id' => $header->id,
            'footer_logo_id' => $footer->id,
        ]);
    }

    public function test_it_creates_a_pending_attempt_for_a_registered_email(): void
    {
        $user = User::factory()->create(['email' => 'ada@example.com']);

        $response = $this->postJson('/api/password/reset-attempts', [
            'tenant_codigo' => $this->tenant->codigo,
            'email' => '  ADA@EXAMPLE.COM  ',
        ]);

        $response
            ->assertAccepted()
            ->assertJsonPath('status', ResetPasswordAttempt::STATUS_PENDING);

        $attempt = ResetPasswordAttempt::query()->sole();

        $this->assertTrue($attempt->user->is($user));
        $this->assertMatchesRegularExpression('/^\d{4}$/', $attempt->codigo);
        $this->assertSame(ResetPasswordAttempt::STATUS_PENDING, $attempt->status);
        Event::assertDispatched(
            PasswordResetRequested::class,
            fn (PasswordResetRequested $event): bool => $event->attemptId === $attempt->id
                && $event->tenantCode === $this->tenant->codigo,
        );
    }

    public function test_it_expires_previous_pending_and_validated_attempts(): void
    {
        $user = User::factory()->create(['email' => 'ada@example.com']);
        $pendingAttempt = $user->resetPasswordAttempts()->create([
            'codigo' => '1234',
        ]);
        $validatedAttempt = $user->resetPasswordAttempts()->create([
            'codigo' => '5678',
            'status' => ResetPasswordAttempt::STATUS_VALIDATED,
        ]);

        $this->postJson('/api/password/reset-attempts', [
            'tenant_codigo' => $this->tenant->codigo,
            'email' => 'ada@example.com',
        ])->assertAccepted();

        $this->assertSame(ResetPasswordAttempt::STATUS_EXPIRED, $pendingAttempt->fresh()->status);
        $this->assertSame(ResetPasswordAttempt::STATUS_EXPIRED, $validatedAttempt->fresh()->status);
        $this->assertSame(1, $user->resetPasswordAttempts()
            ->where('status', ResetPasswordAttempt::STATUS_PENDING)
            ->count());
    }

    public function test_unknown_email_gets_the_same_response_without_creating_an_attempt(): void
    {
        $response = $this->postJson('/api/password/reset-attempts', [
            'tenant_codigo' => $this->tenant->codigo,
            'email' => 'unknown@example.com',
        ]);

        $response
            ->assertAccepted()
            ->assertJsonPath('status', ResetPasswordAttempt::STATUS_PENDING);
        $this->assertDatabaseCount('reset_password_attempts', 0);
        Event::assertNotDispatched(PasswordResetRequested::class);
    }

    public function test_it_validates_the_email(): void
    {
        $this->postJson('/api/password/reset-attempts', [
            'tenant_codigo' => $this->tenant->codigo,
            'email' => 'invalid-email',
        ])->assertUnprocessable()->assertJsonValidationErrors('email');
    }
}
