<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Enums\ConversationStatus;
use App\Enums\PropertyProposalStatus;
use App\Enums\PropertyRequestStatus;
use App\Enums\UserAccountStatus;
use App\Models\City;
use App\Models\Conversation;
use App\Models\Message;
use App\Models\ProfessionalProfile;
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 ConversationActionTest extends TestCase
{
    use RefreshDatabase;

    public function test_non_participant_cannot_update_visit(): void
    {
        [$conversation, $owner, $proposer, $outsider] = $this->createConversationFixture();
        Sanctum::actingAs($outsider);

        $this->postJson("/api/conversations/{$conversation->id}/actions/visit", [
            'visit_status' => 'completed',
        ])->assertForbidden();
    }

    public function test_participant_can_update_visit_and_creates_system_message(): void
    {
        [$conversation, $owner, $proposer] = $this->createConversationFixture();
        Sanctum::actingAs($proposer);

        $response = $this->postJson("/api/conversations/{$conversation->id}/actions/visit", [
            'visit_status' => 'scheduled',
            'visit_date' => now()->addWeek()->toDateString(),
            'visit_time' => '14:30',
            'location_note' => 'Agence centrale',
        ]);

        $response->assertOk()
            ->assertJsonPath('data.conversation.visit_status', 'scheduled');

        $this->assertDatabaseHas('messages', [
            'conversation_id' => $conversation->id,
            'sender_id' => $proposer->id,
            'is_system' => true,
        ]);

        $this->assertTrue(
            Message::query()->where('conversation_id', $conversation->id)->where('is_system', true)->exists()
        );
    }

    public function test_deal_cancelled_does_not_increment_closed_deals(): void
    {
        [$conversation, $owner, $proposer] = $this->createConversationFixture();

        ProfessionalProfile::query()->create([
            'user_id' => $owner->id,
            'professional_name' => 'Owner Co',
            'profile_type' => $owner->account_type?->value ?? 'independent_agent',
            'verification_status' => 'verified',
        ]);
        ProfessionalProfile::query()->create([
            'user_id' => $proposer->id,
            'professional_name' => 'Proposer Co',
            'profile_type' => $proposer->account_type?->value ?? 'independent_agent',
            'verification_status' => 'verified',
        ]);

        Sanctum::actingAs($owner);

        $this->postJson("/api/conversations/{$conversation->id}/actions/close-deal", [
            'outcome' => 'deal_cancelled',
            'reason' => 'Client non intéressé',
        ])->assertOk();

        $this->assertDatabaseHas('professional_profiles', [
            'user_id' => $owner->id,
            'total_closed_deals' => 0,
        ]);
    }

    public function test_close_deal_increments_profiles_for_both_participants(): void
    {
        [$conversation, $owner, $proposer] = $this->createConversationFixture();

        ProfessionalProfile::query()->create([
            'user_id' => $owner->id,
            'professional_name' => 'Owner Co',
            'profile_type' => $owner->account_type?->value ?? 'independent_agent',
            'verification_status' => 'verified',
        ]);
        ProfessionalProfile::query()->create([
            'user_id' => $proposer->id,
            'professional_name' => 'Proposer Co',
            'profile_type' => $proposer->account_type?->value ?? 'independent_agent',
            'verification_status' => 'verified',
        ]);

        Sanctum::actingAs($owner);

        $this->postJson("/api/conversations/{$conversation->id}/actions/close-deal", [
            'outcome' => 'deal_closed',
            'reason' => 'Compromis signé',
        ])->assertOk();

        $this->assertDatabaseHas('professional_profiles', [
            'user_id' => $owner->id,
            'total_closed_deals' => 1,
        ]);
        $this->assertDatabaseHas('professional_profiles', [
            'user_id' => $proposer->id,
            'total_closed_deals' => 1,
        ]);

        $conversation->refresh();
        $this->assertSame(ConversationStatus::DealClosed, $conversation->status);

        $this->assertDatabaseHas('property_requests', [
            'id' => $conversation->request_id,
            'status' => PropertyRequestStatus::Fulfilled->value,
        ]);
    }

    /**
     * @return array{0: Conversation, 1: User, 2: User, 3?: User}
     */
    private function createConversationFixture(): array
    {
        $owner = User::factory()->create(['status' => UserAccountStatus::Approved]);
        $proposer = User::factory()->create(['status' => UserAccountStatus::Approved]);
        $outsider = User::factory()->create(['status' => UserAccountStatus::Approved]);

        $city = City::query()->create(['name' => 'Djerba', 'country' => 'TN']);
        Zone::query()->create(['city_id' => $city->id, 'name' => 'Midoun']);

        $request = PropertyRequest::query()->create([
            'reference' => 'REQ-ACT-1',
            'created_by_user_id' => $owner->id,
            'transaction_type' => 'achat',
            'property_type' => 'villa',
            'city_id' => $city->id,
            'zone_id' => null,
            'title' => 'Demande test',
            'budget_min' => 100,
            'budget_max' => 200,
            'surface_min' => 100,
            'rooms' => 4,
            'bedrooms' => 3,
            'urgency_level' => 'normal',
            'description' => 'Description suffisamment longue pour la demande.',
            'status' => PropertyRequestStatus::Active,
            'expires_at' => now()->addMonth(),
        ]);

        $proposal = $request->proposals()->create([
            'proposed_by_user_id' => $proposer->id,
            'title' => 'Bien',
            'property_type' => 'villa',
            'city_id' => $city->id,
            'zone_id' => null,
            'price' => 150,
            'surface' => 120,
            'description' => 'Proposition test',
            'status' => PropertyProposalStatus::Pending,
        ]);

        $conversation = Conversation::query()->create([
            'request_id' => $request->id,
            'proposal_id' => $proposal->id,
            'requester_user_id' => $owner->id,
            'proposer_user_id' => $proposer->id,
            'title' => 'Test conv',
            'status' => ConversationStatus::DiscussionInProgress,
            'visit_status' => 'none',
            'offer_status' => 'none',
            'commission_status' => 'none',
        ]);

        return [$conversation, $owner, $proposer, $outsider];
    }
}
