<?php

namespace Tests\Feature;

use Illuminate\Support\Carbon;
use Mtc\MercuryDataModels\ModelHasRole;
use Mtc\MercuryDataModels\Tenant;
use Mtc\MercuryDataModels\User;
use Tests\DatabaseTestCase;

class ExpireInvitedUsersTest extends DatabaseTestCase
{
    public function testDeletesUnactivatedInviteOlderThanThreshold(): void
    {
        $user = User::factory()->create(['last_login_at' => null]);
        $site = Tenant::create();
        $this->inviteUser($user, $site, Carbon::now()->subDays(40));

        $this->artisan('users:expire-invitations')->assertExitCode(0);

        $this->assertFalse(User::query()->whereKey($user->id)->exists());
        $this->assertFalse($user->tenants()->wherePivot('tenant_id', $site->id)->exists());
        $this->assertFalse($this->roleAssignmentExists($user));
    }

    public function testKeepsInviteWithinThreshold(): void
    {
        $user = User::factory()->create(['last_login_at' => null]);
        $site = Tenant::create();
        $this->inviteUser($user, $site, Carbon::now()->subDays(5));

        $this->artisan('users:expire-invitations')->assertExitCode(0);

        $this->assertTrue(User::query()->whereKey($user->id)->exists());
    }

    public function testKeepsUserThatHasActivated(): void
    {
        $user = User::factory()->create(['last_login_at' => Carbon::now()->subDays(10)]);
        $site = Tenant::create();
        $this->inviteUser($user, $site, Carbon::now()->subDays(40));

        $this->artisan('users:expire-invitations')->assertExitCode(0);

        $this->assertTrue(User::query()->whereKey($user->id)->exists());
    }

    public function testIgnoresInviteWithoutTimestamp(): void
    {
        $user = User::factory()->create(['last_login_at' => null]);
        $site = Tenant::create();
        $this->inviteUser($user, $site, null);

        $this->artisan('users:expire-invitations')->assertExitCode(0);

        $this->assertTrue(User::query()->whereKey($user->id)->exists());
    }

    public function testKeepsUserWithAnyRecentInvite(): void
    {
        $user = User::factory()->create(['last_login_at' => null]);
        $expiredSite = Tenant::create();
        $freshSite = Tenant::create();
        $this->inviteUser($user, $expiredSite, Carbon::now()->subDays(40));
        $this->inviteUser($user, $freshSite, Carbon::now()->subDays(2));

        $this->artisan('users:expire-invitations')->assertExitCode(0);

        $this->assertTrue(User::query()->whereKey($user->id)->exists());
    }

    public function testRespectsDaysOption(): void
    {
        $user = User::factory()->create(['last_login_at' => null]);
        $site = Tenant::create();
        $this->inviteUser($user, $site, Carbon::now()->subDays(40));

        $this->artisan('users:expire-invitations', ['--days' => 90])->assertExitCode(0);

        $this->assertTrue(User::query()->whereKey($user->id)->exists());
    }

    /**
     * Mirror the invite side effects: a tenant link plus a role assignment.
     */
    private function inviteUser(User $user, Tenant $site, ?Carbon $invitedAt): void
    {
        $user->tenants()->attach($site->id, [
            'role' => 'administrator',
            'created_at' => $invitedAt,
            'updated_at' => $invitedAt,
        ]);

        ModelHasRole::query()->create([
            'model_type' => 'user',
            'model_id' => $user->id,
            'role_id' => 1,
            'tenant_id' => $site->id,
        ]);
    }

    private function roleAssignmentExists(User $user): bool
    {
        return ModelHasRole::query()
            ->where('model_type', 'user')
            ->where('model_id', $user->id)
            ->exists();
    }
}
