<?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\Role;
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);
    }

    // --- MTC Role Restriction Tests ---

    public function testMtcUserSeesMtcRoleInRolesList()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.sites.roles'));

        $response->assertStatus(200);
        $roleNames = collect($response->json())->pluck('name');
        $this->assertContains('mtc', $roleNames->toArray());
    }

    public function testNonMtcUserDoesNotSeeMtcRoleInRolesList()
    {
        // Seed roles and create an Administrator user
        (new GlobalRoleSeed())->run();
        $admin = User::factory()->create();
        $admin->tenants()->attach(tenant('id'), ['role' => 'Administrator']);
        setPermissionsTeamId(tenant('id'));
        $admin->assignRole('Administrator');

        $response = $this->actingAs($admin)
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.sites.roles'));

        $response->assertStatus(200);
        $roleNames = collect($response->json())->pluck('name');
        $this->assertNotContains('mtc', $roleNames->toArray());
    }

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

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.store'), [
                'email' => 'newuser@mtc.co.uk',
                'role' => 'mtc',
            ]);

        $response->assertStatus(200);
        $this->assertInstanceOf(User::class, User::query()->where('email', 'newuser@mtc.co.uk')->first());
    }

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

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

    public function testNonMtcUserCannotStoreWithMtcRole()
    {
        (new GlobalRoleSeed())->run();
        $admin = User::factory()->create();
        $admin->tenants()->attach(tenant('id'), ['role' => 'Administrator']);
        setPermissionsTeamId(tenant('id'));
        $admin->assignRole('Administrator');

        $response = $this->actingAs($admin)
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.settings.site-users.store'), [
                'email' => 'someone@mtc.co.uk',
                'role' => 'mtc',
            ]);

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

    public function testUpdateToMtcRoleWithMtcEmailSucceeds()
    {
        $targetUser = User::factory()->create(['email' => 'target@mtc.co.uk']);
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

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

        $response->assertStatus(200);
    }

    public function testUpdateToMtcRoleWithNonMtcEmailFails()
    {
        $targetUser = User::factory()->create(['email' => 'target@example.com']);
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

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

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

    public function testNonMtcUserCannotUpdateToMtcRole()
    {
        (new GlobalRoleSeed())->run();
        $admin = User::factory()->create();
        $admin->tenants()->attach(tenant('id'), ['role' => 'Administrator']);
        setPermissionsTeamId(tenant('id'));
        $admin->assignRole('Administrator');

        $targetUser = User::factory()->create(['email' => 'target@mtc.co.uk']);
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

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

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