<?php

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

test('data_clerk can create a household 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/households', [
        'branch_id' => $branch->id,
        'name' => 'Moyo Family',
    ]);

    $response->assertCreated()->assertJsonPath('data.name', 'Moyo Family');
    $this->assertDatabaseHas('households', ['name' => 'Moyo Family', 'branch_id' => $branch->id]);
});

test('viewer cannot create a household', function () {
    $branch = Branch::factory()->create();
    $viewer = User::factory()->branchViewer()->create(['branch_id' => $branch->id]);

    $this->actingAs($viewer)->postJson('/api/v1/households', [
        'branch_id' => $branch->id,
        'name' => 'Moyo Family',
    ])->assertStatus(403);
});

test('data_clerk cannot create a household in another branch', function () {
    $ownBranch = Branch::factory()->create();
    $otherBranch = Branch::factory()->create();
    $clerk = User::factory()->dataClerk()->create(['branch_id' => $ownBranch->id]);

    $this->actingAs($clerk)->postJson('/api/v1/households', [
        'branch_id' => $otherBranch->id,
        'name' => 'Moyo Family',
    ])->assertStatus(403);
});

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

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

test('branch_admin sees an empty household list when scoped to another branch', function () {
    $branchA = Branch::factory()->create();
    $branchB = Branch::factory()->create();
    Household::factory()->count(2)->create(['branch_id' => $branchB->id]);
    $adminA = User::factory()->branchAdmin()->create(['branch_id' => $branchA->id]);

    $response = $this->actingAs($adminA)->getJson('/api/v1/households');

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

test('adding a member from another branch to a household is rejected', function () {
    $branchA = Branch::factory()->create();
    $branchB = Branch::factory()->create();
    $household = Household::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/households/{$household->id}/members", [
        'member_id' => $memberB->id,
        'household_role' => 'other',
    ]);

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

test('adding a member already in another household is rejected', function () {
    $branch = Branch::factory()->create();
    $householdA = Household::factory()->create(['branch_id' => $branch->id]);
    $householdB = Household::factory()->create(['branch_id' => $branch->id]);
    $member = Member::factory()->create([
        'branch_id' => $branch->id,
        'household_id' => $householdA->id,
        'household_role' => 'other',
    ]);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $response = $this->actingAs($admin)->postJson("/api/v1/households/{$householdB->id}/members", [
        'member_id' => $member->id,
        'household_role' => 'other',
    ]);

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

test('a member can be added to a household in the same branch', function () {
    $branch = Branch::factory()->create();
    $household = Household::factory()->create(['branch_id' => $branch->id]);
    $member = Member::factory()->create(['branch_id' => $branch->id]);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $response = $this->actingAs($admin)->postJson("/api/v1/households/{$household->id}/members", [
        'member_id' => $member->id,
        'household_role' => 'head',
    ]);

    $response->assertOk();
    $this->assertDatabaseHas('members', [
        'id' => $member->id,
        'household_id' => $household->id,
        'household_role' => 'head',
    ]);
});

test('a household head can be set once the member belongs to the household', function () {
    $branch = Branch::factory()->create();
    $household = Household::factory()->create(['branch_id' => $branch->id]);
    $member = Member::factory()->create([
        'branch_id' => $branch->id,
        'household_id' => $household->id,
        'household_role' => 'head',
    ]);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $response = $this->actingAs($admin)->putJson("/api/v1/households/{$household->id}", [
        'head_member_id' => $member->id,
    ]);

    $response->assertOk()->assertJsonPath('data.head_member.id', $member->id);
});

test('removing the head member from a household clears head_member_id', function () {
    $branch = Branch::factory()->create();
    $household = Household::factory()->create(['branch_id' => $branch->id]);
    $member = Member::factory()->create([
        'branch_id' => $branch->id,
        'household_id' => $household->id,
        'household_role' => 'head',
    ]);
    $household->update(['head_member_id' => $member->id]);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $response = $this->actingAs($admin)->deleteJson("/api/v1/households/{$household->id}/members/{$member->id}");

    $response->assertOk()->assertJsonPath('data.head_member', null);
    $this->assertDatabaseHas('households', ['id' => $household->id, 'head_member_id' => null]);
    $this->assertDatabaseHas('members', ['id' => $member->id, 'household_id' => null, 'household_role' => null]);
});

test('deleting a household clears the household fields on its members', function () {
    $branch = Branch::factory()->create();
    $household = Household::factory()->create(['branch_id' => $branch->id]);
    $member = Member::factory()->create([
        'branch_id' => $branch->id,
        'household_id' => $household->id,
        'household_role' => 'other',
    ]);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

    $this->actingAs($admin)->deleteJson("/api/v1/households/{$household->id}")->assertStatus(204);

    $this->assertSoftDeleted('households', ['id' => $household->id]);
    $this->assertDatabaseHas('members', ['id' => $member->id, 'household_id' => null, 'household_role' => null]);
});

test('members list can be filtered by household_id', function () {
    $branch = Branch::factory()->create();
    $household = Household::factory()->create(['branch_id' => $branch->id]);
    $inHousehold = Member::factory()->create(['branch_id' => $branch->id, 'household_id' => $household->id]);
    Member::factory()->create(['branch_id' => $branch->id]);
    $admin = User::factory()->branchAdmin()->create(['branch_id' => $branch->id]);

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

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

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