<?php

namespace Tests\Feature;

use App\Domain\Files\PatientFileService;
use App\Models\Patient;
use App\Models\PatientFile;
use App\Models\Tenant;
use App\Models\User;
use App\Support\Tenancy;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;

class PatientFileTest extends TestCase
{
    use RefreshDatabase;

    protected Tenant $tenant;
    protected Patient $patient;
    protected User $owner;
    protected string $base;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();
        Storage::fake('local');

        $this->tenant = Tenant::create(['name' => 'Smile', 'slug' => 'smile']);
        $this->tenant->subscription()->create([
            'plan_id' => \App\Models\Plan::first()->id, 'status' => 'trialing',
            'starts_at' => now(), 'current_period_ends_at' => now()->addDays(14),
        ]);

        app(Tenancy::class)->set($this->tenant);
        $this->patient = Patient::factory()->create();
        $this->owner = User::withoutEvents(fn () => User::create([
            'tenant_id' => $this->tenant->id, 'name' => 'O', 'email' => 'o@x.com', 'password' => 'password123',
        ]));
        $this->owner->assignRole('clinic_owner');
        app(Tenancy::class)->forget();

        $this->base = 'http://smile.'.config('tenancy.central_domain');
    }

    public function test_upload_creates_file_with_teeth_tags_and_thumbnail(): void
    {
        $this->actingAs($this->owner)
            ->post($this->base.'/patients/'.$this->patient->id.'/files', [
                'file' => UploadedFile::fake()->image('xray.jpg', 1200, 900),
                'type' => 'xray',
                'teeth' => [16, 17],
                'caption' => 'Bitewing right',
            ])->assertRedirect();

        app(Tenancy::class)->set($this->tenant);
        $file = PatientFile::firstOrFail();

        $this->assertSame('xray', $file->type);
        $this->assertSame([16, 17], $file->teeth);
        Storage::disk('local')->assertExists($file->path);
        $this->assertNotNull($file->thumb_path);
        Storage::disk('local')->assertExists($file->thumb_path);
    }

    public function test_invalid_fdi_tags_are_dropped(): void
    {
        app(Tenancy::class)->set($this->tenant);
        $file = app(PatientFileService::class)->store(
            $this->patient,
            UploadedFile::fake()->image('p.jpg'),
            'photo_before',
            teeth: [16, 99, 19],
        );

        $this->assertSame([16], $file->teeth);
    }

    public function test_pairing_before_and_after(): void
    {
        app(Tenancy::class)->set($this->tenant);
        $svc = app(PatientFileService::class);
        $before = $svc->store($this->patient, UploadedFile::fake()->image('b.jpg'), 'photo_before');
        $after = $svc->store($this->patient, UploadedFile::fake()->image('a.jpg'), 'photo_after');

        $svc->pair($before, $after);

        $this->assertSame($before->id, $after->fresh()->paired_with_id);
        $this->assertSame($after->id, $before->fresh()->after?->id);
    }

    public function test_pairing_wrong_types_is_rejected(): void
    {
        app(Tenancy::class)->set($this->tenant);
        $svc = app(PatientFileService::class);
        $x = $svc->store($this->patient, UploadedFile::fake()->image('x.jpg'), 'xray');
        $after = $svc->store($this->patient, UploadedFile::fake()->image('a.jpg'), 'photo_after');

        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
        $svc->pair($x, $after);
    }

    public function test_files_are_streamed_only_to_the_owning_tenant(): void
    {
        app(Tenancy::class)->set($this->tenant);
        $file = app(PatientFileService::class)->store(
            $this->patient, UploadedFile::fake()->image('p.jpg'), 'photo_before'
        );
        app(Tenancy::class)->forget();

        // Owner of the same clinic: 200
        $this->actingAs($this->owner)
            ->get($this->base.'/files/'.$file->id)
            ->assertOk();

        // A user of another clinic: 404 (global scope hides the row)
        $other = Tenant::create(['name' => 'Other', 'slug' => 'other']);
        $other->subscription()->create([
            'plan_id' => \App\Models\Plan::first()->id, 'status' => 'trialing',
            'starts_at' => now(), 'current_period_ends_at' => now()->addDays(14),
        ]);
        app(Tenancy::class)->set($other);
        $intruder = User::withoutEvents(fn () => User::create([
            'tenant_id' => $other->id, 'name' => 'I', 'email' => 'i@x.com', 'password' => 'password123',
        ]));
        $intruder->assignRole('clinic_owner');
        app(Tenancy::class)->forget();

        $this->actingAs($intruder)
            ->get('http://other.'.config('tenancy.central_domain').'/files/'.$file->id)
            ->assertNotFound();
    }

    public function test_deleting_a_before_unpairs_the_after(): void
    {
        app(Tenancy::class)->set($this->tenant);
        $svc = app(PatientFileService::class);
        $before = $svc->store($this->patient, UploadedFile::fake()->image('b.jpg'), 'photo_before');
        $after = $svc->store($this->patient, UploadedFile::fake()->image('a.jpg'), 'photo_after');
        $svc->pair($before, $after);

        $svc->delete($before);

        $this->assertNull($after->fresh()->paired_with_id);
        $this->assertSoftDeleted('patient_files', ['id' => $before->id]);
    }
}
