<?php

use App\Enums\MembershipStatus;
use App\Models\Branch;
use App\Models\Group;
use App\Models\Household;
use App\Models\Member;
use App\Models\Region;
use App\Models\User;

test('status filter narrows results (single and CSV)', function () {
    $branch = Branch::factory()->create();
    Member::factory()->create(['branch_id' => $branch->id, 'membership_status' => MembershipStatus::Member]);
    Member::factory()->create(['branch_id' => $branch->id, 'membership_status' => MembershipStatus::Visitor]);
    Member::factory()->create(['branch_id' => $branch->id, 'membership_status' => MembershipStatus::Inactive]);
    $superAdmin = User::factory()->superAdmin()->create();

    $single = $this->actingAs($superAdmin)->getJson('/api/v1/members?status=visitor');
    expect($single->json('data'))->toHaveCount(1);

    $csv = $this->actingAs($superAdmin)->getJson('/api/v1/members?status=visitor,inactive');
    expect($csv->json('data'))->toHaveCount(2);
});

test('gender filter narrows results', function () {
    $branch = Branch::factory()->create();
    Member::factory()->create(['branch_id' => $branch->id, 'gender' => 'male']);
    Member::factory()->create(['branch_id' => $branch->id, 'gender' => 'female']);
    $superAdmin = User::factory()->superAdmin()->create();

    $response = $this->actingAs($superAdmin)->getJson('/api/v1/members?gender=female');

    expect($response->json('data'))->toHaveCount(1);
});

test('age_min and age_max translate to a date_of_birth range', function () {
    $branch = Branch::factory()->create();
    $today = today();
    Member::factory()->create(['branch_id' => $branch->id, 'date_of_birth' => $today->copy()->subYears(10)]); // age 10
    Member::factory()->create(['branch_id' => $branch->id, 'date_of_birth' => $today->copy()->subYears(30)]); // age 30
    Member::factory()->create(['branch_id' => $branch->id, 'date_of_birth' => $today->copy()->subYears(70)]); // age 70
    $superAdmin = User::factory()->superAdmin()->create();

    $response = $this->actingAs($superAdmin)->getJson('/api/v1/members?age_min=18&age_max=50');

    expect($response->json('data'))->toHaveCount(1);
});

test('birth_month filter matches regardless of birth year', function () {
    $branch = Branch::factory()->create();
    Member::factory()->create(['branch_id' => $branch->id, 'date_of_birth' => '1990-03-15']);
    Member::factory()->create(['branch_id' => $branch->id, 'date_of_birth' => '2001-03-02']);
    Member::factory()->create(['branch_id' => $branch->id, 'date_of_birth' => '1985-07-04']);
    $superAdmin = User::factory()->superAdmin()->create();

    $response = $this->actingAs($superAdmin)->getJson('/api/v1/members?birth_month=3');

    expect($response->json('data'))->toHaveCount(2);
});

test('group_id filter joins through the group_member pivot', function () {
    $branch = Branch::factory()->create();
    $group = Group::factory()->create(['branch_id' => $branch->id]);
    $inGroup = Member::factory()->create(['branch_id' => $branch->id]);
    Member::factory()->create(['branch_id' => $branch->id]);
    $group->members()->attach($inGroup->id, ['role_in_group' => 'member']);
    $superAdmin = User::factory()->superAdmin()->create();

    $response = $this->actingAs($superAdmin)->getJson("/api/v1/members?group_id={$group->id}");

    expect($response->json('data'))->toHaveCount(1);
    expect($response->json('data.0.id'))->toBe($inGroup->id);
});

test('household_id filter narrows to that household', function () {
    $branch = Branch::factory()->create();
    $household = Household::factory()->create(['branch_id' => $branch->id]);
    Member::factory()->create(['branch_id' => $branch->id, 'household_id' => $household->id, 'household_role' => 'head']);
    Member::factory()->create(['branch_id' => $branch->id]);
    $superAdmin = User::factory()->superAdmin()->create();

    $response = $this->actingAs($superAdmin)->getJson("/api/v1/members?household_id={$household->id}");

    expect($response->json('data'))->toHaveCount(1);
});

test('joined_after and joined_before filter a date_joined range', function () {
    $branch = Branch::factory()->create();
    Member::factory()->create(['branch_id' => $branch->id, 'date_joined' => '2020-01-01']);
    Member::factory()->create(['branch_id' => $branch->id, 'date_joined' => '2022-06-15']);
    Member::factory()->create(['branch_id' => $branch->id, 'date_joined' => '2024-12-31']);
    $superAdmin = User::factory()->superAdmin()->create();

    $response = $this->actingAs($superAdmin)->getJson('/api/v1/members?joined_after=2021-01-01&joined_before=2023-01-01');

    expect($response->json('data'))->toHaveCount(1);
});

test('branch_id and region_id filters are intersected with accessible scope, never widened', function () {
    $regionA = Region::factory()->create();
    $branchA1 = Branch::factory()->create(['region_id' => $regionA->id]);
    $branchB = Branch::factory()->create();
    Member::factory()->create(['branch_id' => $branchA1->id]);
    Member::factory()->create(['branch_id' => $branchB->id]);
    $branchAdminA1 = User::factory()->branchAdmin()->create(['branch_id' => $branchA1->id]);

    // Attempt to widen scope by requesting branch B explicitly — must not leak.
    $response = $this->actingAs($branchAdminA1)->getJson("/api/v1/members?branch_id={$branchB->id}");

    expect($response->json('data'))->toHaveCount(0);
});

test('sort whitelist rejects unknown fields', function () {
    $superAdmin = User::factory()->superAdmin()->create();

    $this->actingAs($superAdmin)->getJson('/api/v1/members?sort=custom_fields')
        ->assertStatus(422)
        ->assertJsonValidationErrors('sort');
});

test('cursor pagination is stable across pages with tied last names', function () {
    $branch = Branch::factory()->create();
    Member::factory()->count(60)->create(['branch_id' => $branch->id, 'last_name' => 'Moyo']);
    $superAdmin = User::factory()->superAdmin()->create();

    $seenIds = [];
    $cursor = null;

    for ($i = 0; $i < 3; $i++) {
        $url = '/api/v1/members?per_page=25'.($cursor ? "&cursor={$cursor}" : '');
        $response = $this->actingAs($superAdmin)->getJson($url);
        $ids = collect($response->json('data'))->pluck('id')->all();
        $seenIds = [...$seenIds, ...$ids];
        $cursor = $response->json('meta.next_cursor');

        if (! $cursor) {
            break;
        }
    }

    expect($seenIds)->toHaveCount(count(array_unique($seenIds)));
    expect(count($seenIds))->toBe(60);
});

test('members/count returns the count for the current filter set', function () {
    $branch = Branch::factory()->create();
    Member::factory()->count(4)->create(['branch_id' => $branch->id, 'membership_status' => MembershipStatus::Member]);
    Member::factory()->count(2)->create(['branch_id' => $branch->id, 'membership_status' => MembershipStatus::Visitor]);
    $superAdmin = User::factory()->superAdmin()->create();

    $response = $this->actingAs($superAdmin)->getJson('/api/v1/members/count?status=member');

    $response->assertOk()->assertJsonPath('data.count', 4);
});

test('viewer can list members but not create them', function () {
    $branch = Branch::factory()->create();
    Member::factory()->create(['branch_id' => $branch->id]);
    $viewer = User::factory()->branchViewer()->create(['branch_id' => $branch->id]);

    $this->actingAs($viewer)->getJson('/api/v1/members')->assertOk();
});

test('unauthenticated request to list members is rejected', function () {
    $this->getJson('/api/v1/members')->assertStatus(401);
});
