<?php

use App\Enums\UserStatus;
use App\Models\AdminLog;
use App\Models\Consultation;
use App\Models\Notification;
use App\Models\Timeline;
use App\Models\TimelineUpdate;
use App\Models\User;
use App\Notifications\AccountReactivatedNotification;
use App\Notifications\PasswordResetByAdminNotification;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification as NotificationFacade;
use Livewire\Volt\Volt;

beforeEach(function () {
    $this->admin = User::factory()->admin()->create();
});

// ===========================================
// Deactivation Tests
// ===========================================

test('admin can deactivate an active individual client', function () {
    $client = User::factory()->individual()->create(['status' => UserStatus::Active]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeactivateModal')
        ->assertSet('showDeactivateModal', true)
        ->call('deactivate')
        ->assertHasNoErrors();

    expect($client->fresh()->status)->toBe(UserStatus::Deactivated);
});

test('admin can deactivate an active company client', function () {
    $client = User::factory()->company()->create(['status' => UserStatus::Active]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeactivateModal')
        ->call('deactivate')
        ->assertHasNoErrors();

    expect($client->fresh()->status)->toBe(UserStatus::Deactivated);
});

test('deactivated user cannot login', function () {
    $user = User::factory()->individual()->create([
        'status' => UserStatus::Deactivated,
        'email' => 'deactivated@example.com',
    ]);

    $this->post('/login', [
        'email' => 'deactivated@example.com',
        'password' => 'password',
    ])->assertSessionHasErrors();

    $this->assertGuest();
});

test('user sessions are invalidated on deactivation', function () {
    $client = User::factory()->individual()->create(['status' => UserStatus::Active]);

    // Create a fake session for the user
    DB::table('sessions')->insert([
        'id' => 'test-session-id',
        'user_id' => $client->id,
        'ip_address' => '127.0.0.1',
        'user_agent' => 'Test',
        'payload' => 'test',
        'last_activity' => time(),
    ]);

    expect(DB::table('sessions')->where('user_id', $client->id)->exists())->toBeTrue();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeactivateModal')
        ->call('deactivate');

    expect(DB::table('sessions')->where('user_id', $client->id)->exists())->toBeFalse();
});

test('admin log entry created on deactivation', function () {
    $client = User::factory()->individual()->create(['status' => UserStatus::Active]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeactivateModal')
        ->call('deactivate');

    expect(AdminLog::where('action', 'deactivate')
        ->where('target_type', 'user')
        ->where('target_id', $client->id)
        ->where('admin_id', $this->admin->id)
        ->exists())->toBeTrue();

    $log = AdminLog::where('action', 'deactivate')->where('target_id', $client->id)->first();
    expect($log->old_values)->toHaveKey('status', 'active');
    expect($log->new_values)->toHaveKey('status', 'deactivated');
});

test('deactivation preserves all user data', function () {
    $client = User::factory()->individual()->create(['status' => UserStatus::Active]);

    // Create related data
    Consultation::factory()->create(['user_id' => $client->id]);
    $timeline = Timeline::factory()->create(['user_id' => $client->id]);
    TimelineUpdate::factory()->create([
        'timeline_id' => $timeline->id,
        'admin_id' => $this->admin->id,
    ]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeactivateModal')
        ->call('deactivate');

    // Verify data is still there
    expect(Consultation::where('user_id', $client->id)->count())->toBe(1);
    expect(Timeline::where('user_id', $client->id)->count())->toBe(1);
    expect($client->fresh())->not->toBeNull();
});

// ===========================================
// Reactivation Tests
// ===========================================

test('admin can reactivate a deactivated individual client', function () {
    $client = User::factory()->individual()->deactivated()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openReactivateModal')
        ->assertSet('showReactivateModal', true)
        ->call('reactivate')
        ->assertHasNoErrors();

    expect($client->fresh()->status)->toBe(UserStatus::Active);
});

test('admin can reactivate a deactivated company client', function () {
    $client = User::factory()->company()->deactivated()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openReactivateModal')
        ->call('reactivate')
        ->assertHasNoErrors();

    expect($client->fresh()->status)->toBe(UserStatus::Active);
});

test('reactivated user can login successfully', function () {
    $client = User::factory()->individual()->create([
        'status' => UserStatus::Deactivated,
        'email' => 'reactivate-test@example.com',
    ]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openReactivateModal')
        ->call('reactivate');

    $this->post('/login', [
        'email' => 'reactivate-test@example.com',
        'password' => 'password',
    ])->assertSessionHasNoErrors();
});

test('email notification queued on reactivation', function () {
    NotificationFacade::fake();

    $client = User::factory()->individual()->deactivated()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openReactivateModal')
        ->call('reactivate')
        ->assertHasNoErrors();

    NotificationFacade::assertSentTo($client, AccountReactivatedNotification::class);
});

test('admin log entry created on reactivation', function () {
    $client = User::factory()->individual()->deactivated()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openReactivateModal')
        ->call('reactivate');

    expect(AdminLog::where('action', 'reactivate')
        ->where('target_type', 'user')
        ->where('target_id', $client->id)
        ->where('admin_id', $this->admin->id)
        ->exists())->toBeTrue();

    $log = AdminLog::where('action', 'reactivate')->where('target_id', $client->id)->first();
    expect($log->old_values)->toHaveKey('status', 'deactivated');
    expect($log->new_values)->toHaveKey('status', 'active');
});

// ===========================================
// Permanent Deletion Tests
// ===========================================

test('delete requires email confirmation', function () {
    $client = User::factory()->individual()->create(['email' => 'delete-test@example.com']);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeleteModal')
        ->assertSet('showDeleteModal', true)
        ->set('deleteConfirmation', 'wrong@email.com')
        ->call('delete')
        ->assertHasErrors(['deleteConfirmation']);

    expect(User::find($client->id))->not->toBeNull();
});

test('successful deletion removes user record permanently', function () {
    $client = User::factory()->individual()->create(['email' => 'permanent-delete@example.com']);
    $clientId = $client->id;

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeleteModal')
        ->set('deleteConfirmation', 'permanent-delete@example.com')
        ->call('delete')
        ->assertHasNoErrors()
        ->assertRedirect(route('admin.clients.individual.index'));

    expect(User::find($clientId))->toBeNull();
});

test('cascade deletion removes user consultations', function () {
    $client = User::factory()->individual()->create(['email' => 'cascade-test@example.com']);
    $consultation = Consultation::factory()->create(['user_id' => $client->id]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeleteModal')
        ->set('deleteConfirmation', 'cascade-test@example.com')
        ->call('delete');

    expect(Consultation::find($consultation->id))->toBeNull();
});

test('cascade deletion removes user timelines and timeline updates', function () {
    $client = User::factory()->individual()->create(['email' => 'cascade-timeline@example.com']);
    $timeline = Timeline::factory()->create(['user_id' => $client->id]);
    $update = TimelineUpdate::factory()->create([
        'timeline_id' => $timeline->id,
        'admin_id' => $this->admin->id,
    ]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeleteModal')
        ->set('deleteConfirmation', 'cascade-timeline@example.com')
        ->call('delete');

    expect(Timeline::find($timeline->id))->toBeNull();
    expect(TimelineUpdate::find($update->id))->toBeNull();
});

test('cascade deletion removes user notifications', function () {
    $client = User::factory()->individual()->create(['email' => 'cascade-notify@example.com']);
    $notification = Notification::factory()->create(['user_id' => $client->id]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeleteModal')
        ->set('deleteConfirmation', 'cascade-notify@example.com')
        ->call('delete');

    expect(Notification::find($notification->id))->toBeNull();
});

test('admin log entry preserved after user deletion', function () {
    $client = User::factory()->individual()->create(['email' => 'log-preserve@example.com']);
    $clientId = $client->id;

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeleteModal')
        ->set('deleteConfirmation', 'log-preserve@example.com')
        ->call('delete');

    expect(AdminLog::where('action', 'delete')
        ->where('target_type', 'user')
        ->where('target_id', $clientId)
        ->where('admin_id', $this->admin->id)
        ->exists())->toBeTrue();
});

test('company client redirects to company index after deletion', function () {
    $client = User::factory()->company()->create(['email' => 'company-delete@example.com']);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeleteModal')
        ->set('deleteConfirmation', 'company-delete@example.com')
        ->call('delete')
        ->assertRedirect(route('admin.clients.company.index'));
});

// ===========================================
// Password Reset Tests
// ===========================================

test('admin can reset user password', function () {
    $client = User::factory()->individual()->create();
    $originalPasswordHash = $client->password;

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openPasswordResetModal')
        ->assertSet('showPasswordResetModal', true)
        ->call('resetPassword')
        ->assertHasNoErrors();

    expect($client->fresh()->password)->not->toBe($originalPasswordHash);
});

test('new password meets minimum requirements', function () {
    $client = User::factory()->individual()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openPasswordResetModal')
        ->call('resetPassword');

    // Password should be 12 characters, hashed
    // We can't check the length directly, but we can verify it's hashed
    expect(strlen($client->fresh()->password))->toBeGreaterThan(50);
});

test('password reset email sent to user', function () {
    NotificationFacade::fake();

    $client = User::factory()->individual()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openPasswordResetModal')
        ->call('resetPassword');

    NotificationFacade::assertSentTo($client, PasswordResetByAdminNotification::class);
});

test('admin log entry created for password reset', function () {
    $client = User::factory()->individual()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openPasswordResetModal')
        ->call('resetPassword');

    expect(AdminLog::where('action', 'password_reset')
        ->where('target_type', 'user')
        ->where('target_id', $client->id)
        ->where('admin_id', $this->admin->id)
        ->exists())->toBeTrue();
});

test('user can login with new password after reset', function () {
    NotificationFacade::fake();

    $client = User::factory()->individual()->create([
        'email' => 'newpass-test@example.com',
    ]);

    $this->actingAs($this->admin);

    // Reset the password
    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openPasswordResetModal')
        ->call('resetPassword');

    // Get the new password from the notification
    NotificationFacade::assertSentTo(
        $client,
        PasswordResetByAdminNotification::class,
        function ($notification) use ($client) {
            // Test that the new password works
            $newPassword = $notification->newPassword;

            auth()->logout();

            // Try logging in with new password
            $response = $this->post('/login', [
                'email' => $client->email,
                'password' => $newPassword,
            ]);

            return true;
        }
    );
});

// ===========================================
// Authorization Tests
// ===========================================

test('non-admin cannot access lifecycle actions', function () {
    $client = User::factory()->individual()->create();

    $this->actingAs($client);

    $this->get(route('admin.clients.individual.show', $client))
        ->assertForbidden();
});

test('admin cannot deactivate their own account', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $this->admin])
        ->call('openDeactivateModal')
        ->call('deactivate')
        ->assertSet('showDeactivateModal', false);

    // Verify status was not changed
    expect($this->admin->fresh()->status)->toBe(UserStatus::Active);

    // Verify no admin log was created for this action
    expect(AdminLog::where('action', 'deactivate')
        ->where('target_id', $this->admin->id)
        ->exists())->toBeFalse();
});

test('admin cannot delete their own account', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $this->admin])
        ->call('openDeleteModal')
        ->set('deleteConfirmation', $this->admin->email)
        ->call('delete')
        ->assertHasErrors(['deleteConfirmation']);

    expect(User::find($this->admin->id))->not->toBeNull();
});

// ===========================================
// Bilingual Tests
// ===========================================

test('confirmation dialogs display in Arabic when locale is ar', function () {
    app()->setLocale('ar');

    $client = User::factory()->individual()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeactivateModal')
        ->assertSee(__('clients.confirm_deactivate'));
});

test('confirmation dialogs display in English when locale is en', function () {
    app()->setLocale('en');

    $client = User::factory()->individual()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.clients.lifecycle-actions', ['client' => $client])
        ->call('openDeactivateModal')
        ->assertSee('Confirm Deactivation');
});

// ===========================================
// Visual Indicator Tests
// ===========================================

test('deactivated user shows visual indicator in individual client list', function () {
    $activeClient = User::factory()->individual()->create([
        'full_name' => 'Active Client',
        'status' => UserStatus::Active,
    ]);
    $deactivatedClient = User::factory()->individual()->deactivated()->create([
        'full_name' => 'Deactivated Client',
    ]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.individual.index')
        ->assertSee('Active Client')
        ->assertSee('Deactivated Client');
});

test('deactivated user shows visual indicator in company client list', function () {
    $activeCompany = User::factory()->company()->create([
        'company_name' => 'Active Company',
        'status' => UserStatus::Active,
    ]);
    $deactivatedCompany = User::factory()->company()->deactivated()->create([
        'company_name' => 'Deactivated Company',
    ]);

    $this->actingAs($this->admin);

    Volt::test('admin.clients.company.index')
        ->assertSee('Active Company')
        ->assertSee('Deactivated Company');
});

// ===========================================
// User Model Method Tests
// ===========================================

test('user model isDeactivated method works correctly', function () {
    $activeUser = User::factory()->individual()->create(['status' => UserStatus::Active]);
    $deactivatedUser = User::factory()->individual()->deactivated()->create();

    expect($activeUser->isDeactivated())->toBeFalse();
    expect($deactivatedUser->isDeactivated())->toBeTrue();
});

test('user model deactivate method changes status', function () {
    $user = User::factory()->individual()->create(['status' => UserStatus::Active]);

    $user->deactivate();

    expect($user->fresh()->status)->toBe(UserStatus::Deactivated);
});

test('user model reactivate method changes status', function () {
    $user = User::factory()->individual()->deactivated()->create();

    $user->reactivate();

    expect($user->fresh()->status)->toBe(UserStatus::Active);
});
