<?php

namespace Tests\Feature;

use App\Models\Appointment;
use App\Models\Dentist;
use App\Models\Patient;
use App\Models\Tenant;
use App\Support\Tenancy;
use Carbon\CarbonImmutable;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PublicBookingTest extends TestCase
{
    use RefreshDatabase;

    protected Tenant $tenant;
    protected Dentist $dentist;
    protected string $base;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();

        $this->tenant = Tenant::create([
            'name' => 'Smile', 'slug' => 'smile', 'timezone' => 'Asia/Baghdad',
            'whatsapp_number' => '+9647701112233',
        ]);
        app(Tenancy::class)->set($this->tenant);

        $this->dentist = Dentist::factory()->create();
        foreach (range(0, 6) as $weekday) {
            $this->dentist->schedules()->create([
                'weekday' => $weekday, 'start_time' => '09:00', 'end_time' => '12:00',
            ]);
        }

        app(Tenancy::class)->forget(); // requests must resolve the tenant themselves
        $this->base = 'http://smile.'.config('tenancy.central_domain');
    }

    protected function tomorrow(string $time): string
    {
        return CarbonImmutable::tomorrow('Asia/Baghdad')->setTimeFromTimeString($time)->format('Y-m-d H:i');
    }

    public function test_booking_page_renders_with_whatsapp_button(): void
    {
        $this->get($this->base.'/book')
            ->assertOk()
            ->assertSee($this->dentist->name)
            ->assertSee('wa.me/9647701112233', false);
    }

    public function test_slots_endpoint_returns_availability(): void
    {
        $this->getJson($this->base.'/book/slots?dentist_id='.$this->dentist->id
                .'&date='.CarbonImmutable::tomorrow('Asia/Baghdad')->toDateString())
            ->assertOk()
            ->assertJsonCount(6, 'data');
    }

    public function test_patient_can_book_and_is_created_by_phone(): void
    {
        $response = $this->post($this->base.'/book', [
            'dentist_id' => $this->dentist->id,
            'starts_at' => $this->tomorrow('09:00'),
            'full_name' => 'Ali Hassan',
            'phone' => '0770 123 4567',
        ]);

        app(Tenancy::class)->set($this->tenant);
        $appointment = Appointment::firstOrFail();
        $response->assertRedirect($this->base.'/book/confirmed/'.$appointment->uuid);

        $this->assertSame('online', $appointment->source);
        $this->assertSame('pending', $appointment->status->value);
        $this->assertSame('9647701234567', $appointment->patient->phone_normalized);
    }

    public function test_returning_phone_reuses_existing_patient(): void
    {
        app(Tenancy::class)->set($this->tenant);
        $existing = Patient::factory()->create(['phone' => '07701234567']);
        app(Tenancy::class)->forget();

        $this->post($this->base.'/book', [
            'dentist_id' => $this->dentist->id,
            'starts_at' => $this->tomorrow('10:00'),
            'full_name' => 'Different Name',
            'phone' => '+964 770 123 4567',
        ]);

        app(Tenancy::class)->set($this->tenant);
        $this->assertSame(1, Patient::count());
        $this->assertSame($existing->id, Appointment::firstOrFail()->patient_id);
    }

    public function test_taken_slot_is_rejected_with_friendly_error(): void
    {
        $this->post($this->base.'/book', [
            'dentist_id' => $this->dentist->id,
            'starts_at' => $this->tomorrow('09:00'),
            'full_name' => 'First', 'phone' => '07701111111',
        ]);

        $this->post($this->base.'/book', [
            'dentist_id' => $this->dentist->id,
            'starts_at' => $this->tomorrow('09:00'),
            'full_name' => 'Second', 'phone' => '07702222222',
        ])->assertSessionHas('error');

        app(Tenancy::class)->set($this->tenant);
        $this->assertSame(1, Appointment::count());
    }

    public function test_patient_can_cancel_via_uuid(): void
    {
        $this->post($this->base.'/book', [
            'dentist_id' => $this->dentist->id,
            'starts_at' => $this->tomorrow('11:30'),
            'full_name' => 'Ali', 'phone' => '07703333333',
        ]);

        app(Tenancy::class)->set($this->tenant);
        $appointment = Appointment::firstOrFail();
        app(Tenancy::class)->forget();

        $this->post($this->base.'/book/cancel/'.$appointment->uuid)
            ->assertRedirect($this->base.'/book');

        app(Tenancy::class)->set($this->tenant);
        $this->assertSame('cancelled', $appointment->fresh()->status->value);
    }
}
