<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Mtc\Modules\Members\Models\Member;
use Mtc\Plugins\Clinic\Src\Models\PatientFile;
use Mtc\Plugins\WeightVerification\Src\Models\WeightVerification;
use Tests\TestCase;

class WeightVerificationUploadTest extends TestCase
{
    use DatabaseTransactions;

    protected function setUp(): void
    {
        parent::setUp();
        // The member Auth facade ('members_auth') is bound by the legacy module
        // hooks at runtime; rebind it for the isolated test application.
        app()->bind('members_auth', function () {
            return new \Mtc\Modules\Members\Classes\Authenticator();
        });
    }

    protected function tearDown(): void
    {
        unset($_SESSION['logged_in'], $_SESSION['member_id']);
        parent::tearDown();
    }

    public function test_submitting_both_photos_stores_them_and_marks_submitted(): void
    {
        Storage::fake('local');

        $member = Member::factory()->create();
        $verification = WeightVerification::query()->create([
            'order_id' => 991000,
            'member_id' => $member->id,
            'status' => WeightVerification::STATUS_PENDING,
        ]);
        $this->loginMember($member);

        $response = $this->post(route('members-weight-verification-store', [], false), [
            'verification_id' => $verification->id,
            'front_photo' => UploadedFile::fake()->image('front.png'),
            'side_photo' => UploadedFile::fake()->image('side.png'),
        ]);

        $response->assertRedirect(route('members-weight-verification', [], false));

        $verification->refresh();
        $this->assertSame(WeightVerification::STATUS_SUBMITTED, $verification->status);
        $this->assertNotNull($verification->front_file_id);
        $this->assertNotNull($verification->side_file_id);
        $this->assertNotNull($verification->submitted_at);

        $this->assertSame(2, PatientFile::query()
            ->where('member_id', $member->id)
            ->whereIn('type', [PatientFile::FILE_TYPE_WEIGHT_FRONT, PatientFile::FILE_TYPE_WEIGHT_SIDE])
            ->count());
    }

    public function test_missing_a_photo_is_rejected_and_status_unchanged(): void
    {
        Storage::fake('local');

        $member = Member::factory()->create();
        $verification = WeightVerification::query()->create([
            'order_id' => 991001,
            'member_id' => $member->id,
            'status' => WeightVerification::STATUS_PENDING,
        ]);
        $this->loginMember($member);

        $response = $this->post(route('members-weight-verification-store', [], false), [
            'verification_id' => $verification->id,
            'front_photo' => UploadedFile::fake()->image('front.png'),
            // side_photo intentionally omitted
        ]);

        $response->assertRedirect(route('members-weight-verification', [], false));

        $verification->refresh();
        $this->assertSame(WeightVerification::STATUS_PENDING, $verification->status);
        $this->assertNull($verification->front_file_id);
    }

    public function test_resubmitting_replaces_and_deletes_superseded_photos(): void
    {
        Storage::fake('local');

        $member = Member::factory()->create();
        $oldFront = $this->makePatientFile($member, PatientFile::FILE_TYPE_WEIGHT_FRONT);
        $oldSide = $this->makePatientFile($member, PatientFile::FILE_TYPE_WEIGHT_SIDE);

        $verification = WeightVerification::query()->create([
            'order_id' => 991002,
            'member_id' => $member->id,
            'status' => WeightVerification::STATUS_RESUBMIT_REQUIRED,
            'front_file_id' => $oldFront->id,
            'side_file_id' => $oldSide->id,
        ]);
        $this->loginMember($member);

        $response = $this->post(route('members-weight-verification-store', [], false), [
            'verification_id' => $verification->id,
            'front_photo' => UploadedFile::fake()->image('front.png'),
            'side_photo' => UploadedFile::fake()->image('side.png'),
        ]);

        $response->assertRedirect(route('members-weight-verification', [], false));

        $verification->refresh();
        $this->assertSame(WeightVerification::STATUS_SUBMITTED, $verification->status);
        $this->assertNotSame($oldFront->id, $verification->front_file_id);
        $this->assertNotSame($oldSide->id, $verification->side_file_id);

        // Superseded photos from the previous attempt are removed.
        $this->assertDatabaseMissing('patient_files', ['id' => $oldFront->id]);
        $this->assertDatabaseMissing('patient_files', ['id' => $oldSide->id]);

        // Only the two new photos remain for the member.
        $this->assertSame(2, PatientFile::query()
            ->where('member_id', $member->id)
            ->whereIn('type', [PatientFile::FILE_TYPE_WEIGHT_FRONT, PatientFile::FILE_TYPE_WEIGHT_SIDE])
            ->count());
    }

    public function test_already_submitted_verification_is_not_overwritten(): void
    {
        Storage::fake('local');

        $member = Member::factory()->create();
        $verification = WeightVerification::query()->create([
            'order_id' => 991003,
            'member_id' => $member->id,
            'status' => WeightVerification::STATUS_SUBMITTED,
            'front_file_id' => 111,
            'side_file_id' => 222,
        ]);
        $submittedAt = $verification->submitted_at;
        $this->loginMember($member);

        // A second submit on an already-submitted record (e.g. a double-submit
        // race) must not clobber the existing photos or move the timestamp.
        $response = $this->post(route('members-weight-verification-store', [], false), [
            'verification_id' => $verification->id,
            'front_photo' => UploadedFile::fake()->image('front.png'),
            'side_photo' => UploadedFile::fake()->image('side.png'),
        ]);

        $response->assertRedirect(route('members-weight-verification', [], false));

        $verification->refresh();
        $this->assertSame(WeightVerification::STATUS_SUBMITTED, $verification->status);
        $this->assertSame(111, $verification->front_file_id);
        $this->assertSame(222, $verification->side_file_id);
        $this->assertEquals($submittedAt, $verification->submitted_at);

        // No stray photos are written when the submit is rejected.
        $this->assertSame(0, PatientFile::query()
            ->where('member_id', $member->id)
            ->whereIn('type', [PatientFile::FILE_TYPE_WEIGHT_FRONT, PatientFile::FILE_TYPE_WEIGHT_SIDE])
            ->count());
    }

    private function makePatientFile(Member $member, string $type): PatientFile
    {
        return PatientFile::query()->create([
            'member_id' => $member->id,
            'type' => $type,
            'title' => 'Old photo',
            'name' => 'old.png',
            'disk' => 'local',
            'date_provided' => '2026-01-01',
        ]);
    }

    private function loginMember(Member $member): void
    {
        $_SESSION['logged_in'] = true;
        $_SESSION['member_id'] = $member->id;
    }
}
