<?php

use App\Enums\Permission;
use App\Enums\WorkspaceUserRole;
use App\Mail\TeamInvitationMail;
use App\Models\TeamInvitation;
use App\Models\User;
use App\Models\Workspace;
use Illuminate\Support\Facades\Mail;
use Inertia\Testing\AssertableInertia as Assert;

function setupTeamUser(string $role, array $permissions = []): array
{
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();
    $workspace->users()->attach($user->id, [
        'role' => $role,
        'permissions' => $permissions,
    ]);
    session(['current_workspace_id' => $workspace->id]);

    return [$user, $workspace];
}

// ── Team Index ──────────────────────────────────────────────

test('owner can view team index page', function () {
    [$user, $workspace] = setupTeamUser(WorkspaceUserRole::Owner);

    $response = $this->actingAs($user)->get(route('team.index'));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('team/Index')
        ->has('members')
        ->has('pendingInvitations')
        ->where('canManageTeam', true)
        ->has('inviteUrl')
        ->has('roles')
    );
});

test('manager with can_manage_team can view team index page', function () {
    [$user] = setupTeamUser(WorkspaceUserRole::Manager, [
        Permission::CanManageTeam => true,
    ]);

    $response = $this->actingAs($user)->get(route('team.index'));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('team/Index')
        ->where('canManageTeam', true)
    );
});

test('manager without can_manage_team can view team index but canManageTeam is false', function () {
    [$user] = setupTeamUser(WorkspaceUserRole::Manager, [
        Permission::CanManageTeam => false,
    ]);

    $response = $this->actingAs($user)->get(route('team.index'));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('team/Index')
        ->where('canManageTeam', false)
    );
});

test('worker receives 404 on team index', function () {
    [$user] = setupTeamUser(WorkspaceUserRole::Worker);

    $response = $this->actingAs($user)->get(route('team.index'));

    $response->assertNotFound();
});

// ── Invite Member ───────────────────────────────────────────

test('owner can invite a new member', function () {
    Mail::fake();
    [$user, $workspace] = setupTeamUser(WorkspaceUserRole::Owner);

    $response = $this->actingAs($user)->post(route('team.invite'), [
        'email' => 'newmember@example.com',
        'role' => 'worker',
    ]);

    $response->assertRedirect();
    $response->assertSessionHas('success', 'Invitation envoyée');

    expect(TeamInvitation::where('workspace_id', $workspace->id)
        ->where('email', 'newmember@example.com')
        ->exists()
    )->toBeTrue();

    Mail::assertQueued(TeamInvitationMail::class, function ($mail) {
        return $mail->hasTo('newmember@example.com');
    });
});

test('manager with can_manage_team can invite a new member', function () {
    Mail::fake();
    [$user, $workspace] = setupTeamUser(WorkspaceUserRole::Manager, [
        Permission::CanManageTeam => true,
    ]);

    $response = $this->actingAs($user)->post(route('team.invite'), [
        'email' => 'newmanager@example.com',
        'role' => 'manager',
    ]);

    $response->assertRedirect();
    $response->assertSessionHas('success', 'Invitation envoyée');

    expect(TeamInvitation::where('workspace_id', $workspace->id)
        ->where('email', 'newmanager@example.com')
        ->where('role', 'manager')
        ->exists()
    )->toBeTrue();
});

test('manager without permission gets 404 on invite', function () {
    [$user] = setupTeamUser(WorkspaceUserRole::Manager, [
        Permission::CanManageTeam => false,
    ]);

    $response = $this->actingAs($user)->post(route('team.invite'), [
        'email' => 'blocked@example.com',
        'role' => 'worker',
    ]);

    $response->assertNotFound();
});

test('worker gets 404 on invite', function () {
    [$user] = setupTeamUser(WorkspaceUserRole::Worker);

    $response = $this->actingAs($user)->post(route('team.invite'), [
        'email' => 'blocked@example.com',
        'role' => 'worker',
    ]);

    $response->assertNotFound();
});

test('cannot invite email already in workspace', function () {
    [$user, $workspace] = setupTeamUser(WorkspaceUserRole::Owner);
    $existingMember = User::factory()->create(['email' => 'existing@example.com']);
    $workspace->users()->attach($existingMember->id, ['role' => 'worker']);

    $response = $this->actingAs($user)->post(route('team.invite'), [
        'email' => 'existing@example.com',
        'role' => 'worker',
    ]);

    $response->assertSessionHasErrors('email');
});

test('invitation creates team invitation record with correct data', function () {
    Mail::fake();
    [$user, $workspace] = setupTeamUser(WorkspaceUserRole::Owner);

    $this->actingAs($user)->post(route('team.invite'), [
        'email' => 'record@example.com',
        'role' => 'manager',
    ]);

    $invitation = TeamInvitation::where('email', 'record@example.com')->first();

    expect($invitation)->not->toBeNull()
        ->and($invitation->workspace_id)->toBe($workspace->id)
        ->and($invitation->role)->toBe('manager')
        ->and($invitation->invited_by)->toBe($user->id)
        ->and($invitation->token)->not->toBeEmpty()
        ->and($invitation->expires_at)->not->toBeNull()
        ->and($invitation->accepted_at)->toBeNull();
});

test('invitation sends email', function () {
    Mail::fake();
    [$user] = setupTeamUser(WorkspaceUserRole::Owner);

    $this->actingAs($user)->post(route('team.invite'), [
        'email' => 'mailto@example.com',
        'role' => 'worker',
    ]);

    Mail::assertQueued(TeamInvitationMail::class, function ($mail) {
        return $mail->hasTo('mailto@example.com');
    });
});

test('cannot send duplicate active invitation to same email', function () {
    Mail::fake();
    [$user, $workspace] = setupTeamUser(WorkspaceUserRole::Owner);

    // Create an existing active invitation
    TeamInvitation::create([
        'workspace_id' => $workspace->id,
        'email' => 'duplicate@example.com',
        'role' => 'worker',
        'invited_by' => $user->id,
        'expires_at' => now()->addDays(7),
    ]);

    $response = $this->actingAs($user)->post(route('team.invite'), [
        'email' => 'duplicate@example.com',
        'role' => 'manager',
    ]);

    $response->assertSessionHasErrors('email');
});
