<?php

use App\Models\Notification;
use App\Models\Permission;
use App\Models\Role;
use App\Models\User;
use App\Services\SystemConfig\SystemConfigService;
use Illuminate\Support\Facades\Cache;

beforeEach(function () {
    $ref = new ReflectionClass(SystemConfigService::class);
    $prop = $ref->getProperty('resolvedSettings');
    $prop->setAccessible(true);
    $prop->setValue(null, null);
    Cache::flush();
});

function makeNotificationAdmin(): User
{
    $role = Role::firstOrCreate(['name' => 'Developer', 'guard_name' => 'web']);
    $user = User::factory()->create();
    $user->assignRole($role);

    foreach (['view notification center', 'manage notification center'] as $name) {
        $perm = Permission::firstOrCreate(['name' => $name, 'guard_name' => 'web']);
        $user->givePermissionTo($perm);
    }

    return $user;
}

function makeNotificationViewer(): User
{
    $user = User::factory()->create();
    $perm = Permission::firstOrCreate(['name' => 'view notification center', 'guard_name' => 'web']);
    $user->givePermissionTo($perm);

    return $user;
}

function makeNotificationForUser(User $user): Notification
{
    $role = Role::firstOrCreate(['name' => 'User', 'guard_name' => 'web']);

    $notification = Notification::create([
        'title'     => 'Test Notice',
        'message'   => 'Hello',
        'recipient' => 'all',
        'type'      => 'info',
        'created_by' => $user->id,
    ]);

    // Attach pivot row so the user sees it
    \DB::table('system_notification_user')->insert([
        'notification_id' => $notification->id,
        'user_id'         => $user->id,
        'read_at'         => null,
        'deleted_at'      => null,
    ]);

    return $notification;
}

// ── Access control ────────────────────────────────────────────────────────────

test('guest cannot view notification center', function () {
    $this->get('/notification-center')->assertRedirect('/login');
});

test('user without permission is forbidden from notification center', function () {
    $user = User::factory()->create();

    $this->actingAs($user)->get('/notification-center')->assertForbidden();
});

test('user with view permission can access notification center', function () {
    $user = makeNotificationViewer();

    $this->actingAs($user)->get('/notification-center')->assertOk();
});

// ── Store (broadcast) ─────────────────────────────────────────────────────────

test('viewer without manage permission cannot broadcast notifications', function () {
    $viewer = makeNotificationViewer();
    Role::firstOrCreate(['name' => 'User', 'guard_name' => 'web']);

    $this->actingAs($viewer)
        ->postJson('/notification-center', [
            'title'     => 'Test',
            'message'   => 'Msg',
            'recipient' => 'User',
            'type'      => 'info',
        ])
        ->assertForbidden();
});

test('admin can broadcast a notification', function () {
    $admin = makeNotificationAdmin();
    Role::firstOrCreate(['name' => 'User', 'guard_name' => 'web']);

    $this->actingAs($admin)
        ->postJson('/notification-center', [
            'title'     => 'Important Update',
            'message'   => 'Please read.',
            'recipient' => 'User',
            'type'      => 'info',
        ])
        ->assertOk()
        ->assertJsonPath('success', true);

    expect(Notification::where('title', 'Important Update')->count())->toBe(1);
});

test('store rejects unknown notification type', function () {
    $admin = makeNotificationAdmin();
    Role::firstOrCreate(['name' => 'User', 'guard_name' => 'web']);

    $this->actingAs($admin)
        ->postJson('/notification-center', [
            'title'     => 'Bad Type',
            'message'   => 'Msg',
            'recipient' => 'User',
            'type'      => 'xss-alert',
        ])
        ->assertStatus(422);
});

test('store requires title and message', function () {
    $admin = makeNotificationAdmin();

    $this->actingAs($admin)
        ->postJson('/notification-center', ['type' => 'info'])
        ->assertStatus(422);
});

// ── Mark as read ──────────────────────────────────────────────────────────────

test('user can mark a notification as read', function () {
    $user = makeNotificationViewer();
    $notification = makeNotificationForUser($user);

    $this->actingAs($user)
        ->patchJson(route('notification-center.read', $notification->id))
        ->assertOk()
        ->assertJsonPath('success', true);
});

test('guest cannot mark notifications as read', function () {
    $notification = Notification::create([
        'title' => 'X', 'message' => 'Y', 'recipient' => 'all', 'type' => 'info',
    ]);

    // JSON requests return 401 Unauthorized (not a redirect) when unauthenticated
    $this->patchJson(route('notification-center.read', $notification->id))
        ->assertUnauthorized();
});

// ── Mark all as read ──────────────────────────────────────────────────────────

test('user can mark all notifications as read', function () {
    $user = makeNotificationViewer();

    $this->actingAs($user)
        ->patchJson(route('notification-center.read-all'))
        ->assertOk()
        ->assertJsonPath('success', true);
});

// ── Personal delete ───────────────────────────────────────────────────────────

test('user can delete (hide) a notification from their view', function () {
    $user = makeNotificationViewer();
    $notification = makeNotificationForUser($user);

    $this->actingAs($user)
        ->deleteJson(route('notification-center.destroy', $notification->id))
        ->assertOk()
        ->assertJsonPath('success', true);
});

// ── Feature flag ──────────────────────────────────────────────────────────────

test('feature disabled blocks regular viewers but allows manage-global-settings users', function () {
    app(SystemConfigService::class)->update(['feature_notification_center' => false]);

    $viewer = makeNotificationViewer();

    $this->actingAs($viewer)
        ->get('/notification-center')
        ->assertForbidden();
});

test('feature flag disabled still allows users with manage global settings', function () {
    app(SystemConfigService::class)->update(['feature_notification_center' => false]);

    $admin = makeNotificationViewer();
    $perm = Permission::firstOrCreate(['name' => 'manage global settings', 'guard_name' => 'web']);
    $admin->givePermissionTo($perm);

    $this->actingAs($admin)
        ->get('/notification-center')
        ->assertOk();
});

// ── Recent notifications API ──────────────────────────────────────────────────

test('recent notifications endpoint returns json with unread count', function () {
    $user = makeNotificationViewer();

    $this->actingAs($user)
        ->getJson('/notification-center/api/recent')
        ->assertOk()
        ->assertJsonStructure(['success', 'unread_count', 'notifications', 'has_more']);
});

test('recent notifications content is escaped', function () {
    $user = makeNotificationViewer();

    $notification = Notification::create([
        'title'      => '<script>alert(1)</script>',
        'message'    => '<b>bold</b>',
        'recipient'  => 'all',
        'type'       => 'info',
        'created_by' => $user->id,
    ]);

    \DB::table('system_notification_user')->insert([
        'notification_id' => $notification->id,
        'user_id'         => $user->id,
        'read_at'         => null,
        'deleted_at'      => null,
    ]);

    $response = $this->actingAs($user)
        ->getJson('/notification-center/api/recent')
        ->json();

    $titles = collect($response['notifications'])->pluck('title')->all();
    // Title must be HTML-entity-escaped, not raw script tag
    foreach ($titles as $t) {
        expect($t)->not->toContain('<script>');
    }
});
