<?php

namespace Tests\Feature;

use App\Models\Association;
use App\Models\Org;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class UserAssociationAccessTest extends TestCase
{
    use RefreshDatabase;

    public function test_user_can_have_only_one_association_per_org(): void
    {
        $org = Org::factory()->create();
        $user = User::factory()->create();
        $association1 = Association::factory()->create(['org_id' => $org->id]);
        $association2 = Association::factory()->create(['org_id' => $org->id]);

        // Associate user with organization
        $user->orgs()->attach($org);

        // Set first association
        $user->setAssociationInOrg($org, $association1);
        $this->assertTrue($user->hasAssociationInOrg($org));
        $this->assertEquals($association1->id, $user->getAssociationInOrg($org)->id);

        // Set second association (should replace first)
        $user->setAssociationInOrg($org, $association2);
        $this->assertTrue($user->hasAssociationInOrg($org));
        $this->assertEquals($association2->id, $user->getAssociationInOrg($org)->id);

        // Verify only one association per org
        $this->assertEquals(1, $user->associations()->wherePivot('org_id', $org->id)->count());
    }

    public function test_user_can_have_different_associations_in_different_orgs(): void
    {
        $org1 = Org::factory()->create();
        $org2 = Org::factory()->create();
        $user = User::factory()->create();
        $association1 = Association::factory()->create(['org_id' => $org1->id]);
        $association2 = Association::factory()->create(['org_id' => $org2->id]);

        // Associate user with both organizations
        $user->orgs()->attach([$org1->id, $org2->id]);

        // Set different associations in each org
        $user->setAssociationInOrg($org1, $association1);
        $user->setAssociationInOrg($org2, $association2);

        $this->assertTrue($user->hasAssociationInOrg($org1));
        $this->assertTrue($user->hasAssociationInOrg($org2));
        $this->assertEquals($association1->id, $user->getAssociationInOrg($org1)->id);
        $this->assertEquals($association2->id, $user->getAssociationInOrg($org2)->id);
    }

    public function test_removing_association_from_user(): void
    {
        $org = Org::factory()->create();
        $user = User::factory()->create();
        $association = Association::factory()->create(['org_id' => $org->id]);

        // Associate user with organization and association
        $user->orgs()->attach($org);
        $user->setAssociationInOrg($org, $association);

        $this->assertTrue($user->hasAssociationInOrg($org));

        // Remove association
        $user->setAssociationInOrg($org, null);

        $this->assertFalse($user->hasAssociationInOrg($org));
        $this->assertNull($user->getAssociationInOrg($org));
    }

    public function test_user_without_association_returns_false(): void
    {
        $org = Org::factory()->create();
        $user = User::factory()->create();

        // Associate user with organization but no association
        $user->orgs()->attach($org);

        $this->assertFalse($user->hasAssociationInOrg($org));
        $this->assertNull($user->getAssociationInOrg($org));
    }

    public function test_association_users_relationship(): void
    {
        $org = Org::factory()->create();
        $user1 = User::factory()->create();
        $user2 = User::factory()->create();
        $association = Association::factory()->create(['org_id' => $org->id]);

        // Associate users with organization
        $user1->orgs()->attach($org);
        $user2->orgs()->attach($org);

        // Set association for both users
        $user1->setAssociationInOrg($org, $association);
        $user2->setAssociationInOrg($org, $association);

        // Test the association's users relationship
        $associationUsers = $association->users;
        $this->assertCount(2, $associationUsers);
        $this->assertTrue($associationUsers->contains($user1));
        $this->assertTrue($associationUsers->contains($user2));
    }
}
