<?php

use App\Models\Branch;
use App\Models\Group;
use App\Models\Member;
use App\Models\User;

test('data_clerk can create a branch group in their own branch', function () {
    $branch = Branch::factory()->create();
    $clerk = User::factory()->dataClerk()->create(['branch_id' => $branch->id]);

    $response = $this->actingAs($clerk)->postJson('/api/v1/groups', [
        'branch_id' => $branch->id,
        'name' => 'Choir',
        'type' => 'ministry',
    ]);

    $response->assertCreated()->assertJsonPath('data.name', 'Choir');
});

test('branch_admin cannot create an organization-wide group', function () {
    $branch = Branch::factory()->create();
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $this->actingAs($admin)->postJson('/api/v1/groups', [
        'branch_id' => null,
        'name' => 'HQ Media Team',
        'type' => 'department',
    ])->assertStatus(403);
});

test('super_admin can create an organization-wide group', function () {
    $superAdmin = User::factory()->superAdmin()->create();

    $response = $this->actingAs($superAdmin)->postJson('/api/v1/groups', [
        'branch_id' => null,
        'name' => 'HQ Media Team',
        'type' => 'department',
    ]);

    $response->assertCreated();
    $this->assertDatabaseHas('groups', ['name' => 'HQ Media Team', 'branch_id' => null]);
});

test('organization-wide groups are visible to branch-scoped users', function () {
    Group::factory()->organizationWide()->create(['name' => 'HQ Media Team']);
    $branch = Branch::factory()->create();
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $response = $this->actingAs($admin)->getJson('/api/v1/groups');

    $response->assertOk();
    expect(collect($response->json('data'))->pluck('name'))->toContain('HQ Media Team');
});

test('branch_admin cannot update an organization-wide group', function () {
    $group = Group::factory()->organizationWide()->create();
    $branch = Branch::factory()->create();
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $this->actingAs($admin)->putJson("/api/v1/groups/{$group->id}", [
        'name' => 'Renamed',
    ])->assertStatus(403);
});

test('branch_admin of branch A gets 404 on a branch B group', function () {
    $branchA = Branch::factory()->create();
    $branchB = Branch::factory()->create();
    $groupB = Group::factory()->create(['branch_id' => $branchB->id]);
    $adminA = User::factory()->branchAdmin()->create(['branch_id' => $branchA->id]);

    $this->actingAs($adminA)->getJson("/api/v1/groups/{$groupB->id}")->assertStatus(404);
});

test('adding a member from another branch to a branch group is rejected', function () {
    $branchA = Branch::factory()->create();
    $branchB = Branch::factory()->create();
    $group = Group::factory()->create(['branch_id' => $branchA->id]);
    $memberB = Member::factory()->create(['branch_id' => $branchB->id]);
    $superAdmin = User::factory()->superAdmin()->create();

    $response = $this->actingAs($superAdmin)->postJson("/api/v1/groups/{$group->id}/members", [
        'member_id' => $memberB->id,
    ]);

    $response->assertStatus(422)->assertJsonValidationErrors('member_id');
});

test('a member can be added to a group and their role changed', function () {
    $branch = Branch::factory()->create();
    $group = Group::factory()->create(['branch_id' => $branch->id]);
    $member = Member::factory()->create(['branch_id' => $branch->id]);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $this->actingAs($admin)->postJson("/api/v1/groups/{$group->id}/members", [
        'member_id' => $member->id,
        'role_in_group' => 'member',
    ])->assertCreated();

    $this->assertDatabaseHas('group_member', [
        'group_id' => $group->id,
        'member_id' => $member->id,
        'role_in_group' => 'member',
    ]);

    $response = $this->actingAs($admin)->putJson("/api/v1/groups/{$group->id}/members/{$member->id}", [
        'role_in_group' => 'leader',
    ]);

    $response->assertOk()->assertJsonPath('data.role_in_group', 'leader');
});

test('a member can be removed from a group', function () {
    $branch = Branch::factory()->create();
    $group = Group::factory()->create(['branch_id' => $branch->id]);
    $member = Member::factory()->create(['branch_id' => $branch->id]);
    $group->members()->attach($member->id, ['role_in_group' => 'member']);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $this->actingAs($admin)->deleteJson("/api/v1/groups/{$group->id}/members/{$member->id}")->assertStatus(204);

    $this->assertDatabaseMissing('group_member', ['group_id' => $group->id, 'member_id' => $member->id]);
});

test('a member cannot be added to the same group twice', function () {
    $branch = Branch::factory()->create();
    $group = Group::factory()->create(['branch_id' => $branch->id]);
    $member = Member::factory()->create(['branch_id' => $branch->id]);
    $group->members()->attach($member->id, ['role_in_group' => 'member']);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $this->actingAs($admin)->postJson("/api/v1/groups/{$group->id}/members", [
        'member_id' => $member->id,
        'role_in_group' => 'assistant',
    ])->assertCreated();

    expect($group->members()->count())->toBe(1);
    $this->assertDatabaseHas('group_member', [
        'group_id' => $group->id,
        'member_id' => $member->id,
        'role_in_group' => 'assistant',
    ]);
});

test('members list can be filtered by group_id', 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']);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

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

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

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