<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Enums\PropertyRequestStatus;
use App\Enums\UserAccountStatus;
use App\Models\City;
use App\Models\PropertyRequest;
use App\Models\User;
use App\Models\Zone;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;

class PropertyRequestIndexTest extends TestCase
{
    use RefreshDatabase;

    public function test_guest_cannot_list_property_requests(): void
    {
        $this->getJson('/api/property-requests')->assertUnauthorized();
    }

    public function test_pending_user_cannot_list_property_requests(): void
    {
        $user = User::factory()->create(['status' => UserAccountStatus::Pending]);
        Sanctum::actingAs($user);

        $this->getJson('/api/property-requests')->assertForbidden();
    }

    public function test_lists_only_active_non_expired_requests_newest_first(): void
    {
        $viewer = User::factory()->create(['status' => UserAccountStatus::Approved]);
        $owner = User::factory()->create(['status' => UserAccountStatus::Approved, 'name' => 'Agence Test']);
        $city = City::query()->create(['name' => 'Djerba', 'country' => 'TN']);

        $older = $this->makeRequest($owner, $city->id, ['title' => 'Ancienne demande']);
        $older->forceFill(['created_at' => now()->subDays(2)])->save();

        $newer = $this->makeRequest($owner, $city->id, ['title' => 'Demande récente']);
        $newer->forceFill(['created_at' => now()->subHour()])->save();

        $this->makeRequest($owner, $city->id, [
            'title' => 'Expirée',
            'status' => PropertyRequestStatus::Active,
            'expires_at' => now()->subDay(),
        ]);

        $this->makeRequest($owner, $city->id, [
            'title' => 'Inactive',
            'status' => PropertyRequestStatus::Expired,
            'expires_at' => now()->addMonth(),
        ]);

        Sanctum::actingAs($viewer);

        $response = $this->getJson('/api/property-requests');

        $response->assertOk()
            ->assertJsonCount(2, 'data')
            ->assertJsonPath('data.0.id', $newer->id)
            ->assertJsonPath('data.1.id', $older->id)
            ->assertJsonPath('data.0.publisher.name', 'Agence Test')
            ->assertJsonPath('meta.per_page', 15);

        $response->assertJsonStructure([
            'data' => [
                [
                    'id',
                    'reference',
                    'title',
                    'property_type',
                    'city_name',
                    'budget_max',
                    'urgency_level',
                    'status',
                    'status_label',
                    'proposals_count',
                    'created_at',
                    'publisher' => ['id', 'name', 'account_type'],
                ],
            ],
            'links',
            'meta' => ['current_page', 'last_page', 'per_page', 'total'],
        ]);
    }

    public function test_filters_by_property_type_city_zone_budget_and_urgency(): void
    {
        $viewer = User::factory()->create(['status' => UserAccountStatus::Approved]);
        $owner = User::factory()->create(['status' => UserAccountStatus::Approved]);
        $city = City::query()->create(['name' => 'Tunis', 'country' => 'TN']);
        $zone = Zone::query()->create(['city_id' => $city->id, 'name' => 'Lac']);

        $match = $this->makeRequest($owner, $city->id, [
            'property_type' => 'villa',
            'zone_id' => $zone->id,
            'budget_max' => 500_000,
            'urgency_level' => 'urgent',
            'title' => 'Villa urgente',
        ]);

        $this->makeRequest($owner, $city->id, [
            'property_type' => 'appartement',
            'zone_id' => $zone->id,
            'budget_max' => 400_000,
            'urgency_level' => 'urgent',
            'title' => 'Appartement',
        ]);

        $this->makeRequest($owner, $city->id, [
            'property_type' => 'villa',
            'zone_id' => $zone->id,
            'budget_max' => 900_000,
            'urgency_level' => 'normal',
            'title' => 'Villa hors budget',
        ]);

        Sanctum::actingAs($viewer);

        $query = http_build_query([
            'property_type' => 'villa',
            'city_id' => $city->id,
            'zone_id' => $zone->id,
            'budget_max' => 600_000,
            'urgency_level' => 'urgent',
        ]);

        $this->getJson('/api/property-requests?'.$query)
            ->assertOk()
            ->assertJsonCount(1, 'data')
            ->assertJsonPath('data.0.id', $match->id)
            ->assertJsonPath('data.0.city_name', 'Tunis')
            ->assertJsonPath('data.0.zone_name', 'Lac');
    }

    public function test_filters_by_urgency_level(): void
    {
        $viewer = User::factory()->create(['status' => UserAccountStatus::Approved]);
        $owner = User::factory()->create(['status' => UserAccountStatus::Approved]);
        $city = City::query()->create(['name' => 'Nabeul', 'country' => 'TN']);

        $urgent = $this->makeRequest($owner, $city->id, [
            'urgency_level' => 'urgent',
            'title' => 'Demande urgente',
        ]);
        $this->makeRequest($owner, $city->id, [
            'urgency_level' => 'normal',
            'title' => 'Demande normale',
        ]);

        Sanctum::actingAs($viewer);

        $this->getJson('/api/property-requests?urgency_level=urgent')
            ->assertOk()
            ->assertJsonCount(1, 'data')
            ->assertJsonPath('data.0.id', $urgent->id);
    }

    public function test_pagination_respects_per_page(): void
    {
        $viewer = User::factory()->create(['status' => UserAccountStatus::Approved]);
        $owner = User::factory()->create(['status' => UserAccountStatus::Approved]);
        $city = City::query()->create(['name' => 'Sfax', 'country' => 'TN']);

        for ($i = 0; $i < 20; $i++) {
            $this->makeRequest($owner, $city->id, ['title' => "Demande {$i}"]);
        }

        Sanctum::actingAs($viewer);

        $this->getJson('/api/property-requests?per_page=10&page=2')
            ->assertOk()
            ->assertJsonPath('meta.per_page', 10)
            ->assertJsonPath('meta.current_page', 2)
            ->assertJsonCount(10, 'data');
    }

    /**
     * @param  array<string, mixed>  $overrides
     */
    private function makeRequest(User $owner, int $cityId, array $overrides = []): PropertyRequest
    {
        return PropertyRequest::query()->create(array_merge([
            'reference' => 'REQ-TEST-'.strtoupper(substr(uniqid(), -4)),
            'created_by_user_id' => $owner->id,
            'transaction_type' => 'achat',
            'property_type' => 'villa',
            'city_id' => $cityId,
            'zone_id' => null,
            'title' => 'Demande test',
            'budget_min' => 300_000,
            'budget_max' => 500_000,
            'surface_min' => 100,
            'rooms' => 4,
            'bedrooms' => 3,
            'urgency_level' => 'normal',
            'description' => 'Description suffisamment longue pour la demande.',
            'status' => PropertyRequestStatus::Active,
            'expires_at' => now()->addMonth(),
        ], $overrides));
    }
}
