<?php

namespace Tests\Feature\Controllers;

use App\Master\SiteManager;
use App\Notifications\AddedToSiteNotification;
use App\Tier;
use Database\Seeders\Global\GlobalRoleSeed;
use Illuminate\Support\Facades\Notification;
use Mtc\MercuryDataModels\Tenant;
use Mtc\MercuryDataModels\User;
use Tests\DatabaseTestCase;
use Tests\UserForTenant;

class SiteUserControllerTest extends DatabaseTestCase
{
    use UserForTenant;

    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testShow()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.settings.site-users.show'));

        $response->assertStatus(200);
        $this->assertEquals(2, $response->json('data.limit'));
        $this->assertIsArray($response->json('data.users'));
        $this->assertCount(1, $response->json('data.users'));
    }

    public function testStore()
    {
        Notification::fake();
        (new GlobalRoleSeed())->run();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.store'), [
                'email' => 'jdoe@example.com',
                'role' => 'Administrator',
            ]);

        $response->assertStatus(200);

        $user = User::query()->where('email', 'jdoe@example.com')->first();
        $this->assertInstanceOf(User::class, $user);
        $this->assertEquals(1, (new SiteManager())->getSiteUserCount(tenant('id')));
        Notification::assertSentTo($user, AddedToSiteNotification::class);
    }

    public function testUpdate()
    {
        $user = User::factory()->create();
        $user->tenants()->attach(tenant('id'));

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.update'), [
                'userId' => $user->id,
                'role' => 'Editor'
            ]);

        $response->assertStatus(200);
    }

    public function testDestroy()
    {
        $user = User::factory()->create();
        $user->tenants()->attach(tenant('id'));

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('tenant.settings.site-users.destroy'), [
                'userId' => $user->id,
            ]);

        $response->assertStatus(200);
    }

    public function testFailsUserCreationWhenExceedsUserLimit()
    {
        Notification::fake();
        $tenant = tenant();
        Tenant::query()->where('id', $tenant->id)->update([
            'tier' => Tier::LITE->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.store'), [
                'email' => 'jdoe@example.com',
                'role' => 'Administrator',
            ]);
        $response->assertStatus(200);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.store'), [
                'email' => 'jdoe2@example.com',
                'role' => 'Administrator',
            ]);
        $response->assertStatus(200);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.store'), [
                'email' => 'jdoe3@example.com',
                'role' => 'Administrator',
            ]);
        $response->assertStatus(403);
    }

    public function testResendInvite()
    {
        Notification::fake();

        $user = User::factory()->create(['last_login_at' => null]);
        $user->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.resend'), [
                'userId' => $user->id,
            ]);

        $response->assertStatus(200);
        $response->assertJson(['message' => 'Invitation resent successfully']);

        Notification::assertSentTo($user, AddedToSiteNotification::class);
    }

    public function testResendInviteFailsForUserNotOnSite()
    {
        Notification::fake();

        $user = User::factory()->create(['last_login_at' => null]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.resend'), [
                'userId' => $user->id,
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['userId']);

        Notification::assertNotSentTo($user, AddedToSiteNotification::class);
    }

    public function testResendInviteFailsForNonExistentUser()
    {
        Notification::fake();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.resend'), [
                'userId' => 999999,
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['userId']);
    }

    public function testResendInviteFailsForUserWhoHasLoggedIn()
    {
        Notification::fake();

        $user = User::factory()->create(['last_login_at' => now()]);
        $user->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.resend'), [
                'userId' => $user->id,
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['userId']);

        Notification::assertNotSentTo($user, AddedToSiteNotification::class);
    }
}
