<?php

declare(strict_types=1);

use App\Models\Tenant;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;

/**
 * Тесты PATCH /api/auth/me/notification-preferences (Settings → Уведомления).
 *
 * Принимает {prefs: {event: {channel: bool}}, sound_enabled?: bool}.
 * Валидация: события ∈ ALL_EVENTS (8), каналы ∈ {inapp, push, email}.
 * Незадекларированные ключи отбрасываются (защита от schema-pollution).
 */
uses(DatabaseTransactions::class);

beforeEach(function () {
    $this->tenant = Tenant::factory()->create();
    $this->user = User::factory()->create(['tenant_id' => $this->tenant->id]);
    $this->actingAs($this->user);
});

test('PATCH без auth: 401', function () {
    auth()->logout();
    $this->patchJson('/api/auth/me/notification-preferences', [
        'prefs' => ['new_lead' => ['email' => true]],
    ])->assertStatus(401);
});

test('PATCH успех: сохраняет prefs + возвращает user', function () {
    $response = $this->patchJson('/api/auth/me/notification-preferences', [
        'prefs' => [
            'new_lead' => ['inapp' => true, 'push' => false, 'email' => true],
            'reminder' => ['inapp' => true, 'email' => true],
        ],
        'sound_enabled' => false,
    ]);

    $response->assertOk();
    $userResp = $response->json('user');
    expect($userResp['notification_preferences']['new_lead']['email'])->toBeTrue();
    expect($userResp['notification_preferences']['new_lead']['inapp'])->toBeTrue();
    expect($userResp['notification_preferences']['new_lead']['push'])->toBeFalse();
    expect($userResp['sound_enabled'])->toBeFalse();
});

test('PATCH: неизвестные events отбрасываются', function () {
    $response = $this->patchJson('/api/auth/me/notification-preferences', [
        'prefs' => [
            'new_lead' => ['email' => true],
            'fake_event' => ['email' => true],  // не в ALL_EVENTS — должно отброситься
        ],
    ]);

    $response->assertOk();
    $prefs = $response->json('user.notification_preferences');
    expect($prefs)->toHaveKey('new_lead');
    expect($prefs)->not->toHaveKey('fake_event');
});

test('PATCH: неизвестные каналы отбрасываются', function () {
    $response = $this->patchJson('/api/auth/me/notification-preferences', [
        'prefs' => [
            'new_lead' => [
                'email' => true,
                'sms' => true,    // SMS — не в нашей schema
                'webhook' => true, // тоже не из schema
            ],
        ],
    ]);

    $response->assertOk();
    $prefs = $response->json('user.notification_preferences.new_lead');
    expect($prefs)->toHaveKey('email');
    expect($prefs)->not->toHaveKey('sms');
    expect($prefs)->not->toHaveKey('webhook');
});

test('PATCH: 422 без prefs', function () {
    $this->patchJson('/api/auth/me/notification-preferences', [
        'sound_enabled' => true,
    ])->assertStatus(422);
});

test('PATCH: sound_enabled опционален (без него не меняется)', function () {
    $this->user->update(['sound_enabled' => true]);

    $response = $this->patchJson('/api/auth/me/notification-preferences', [
        'prefs' => ['new_lead' => ['email' => true]],
    ]);

    $response->assertOk();
    expect($response->json('user.sound_enabled'))->toBeTrue();
});

test('GET /api/auth/me возвращает notification_preferences + sound_enabled', function () {
    $response = $this->getJson('/api/auth/me');

    $response->assertOk();
    $user = $response->json('user');
    expect($user)->toHaveKey('notification_preferences');
    expect($user)->toHaveKey('sound_enabled');
    // schema-default: events (reminder removed).
    expect($user['notification_preferences'])->toHaveKey('new_lead');
    expect($user['notification_preferences'])->toHaveKey('low_balance');
});

test('PATCH: prefs.* должен быть объект (не строка)', function () {
    $this->patchJson('/api/auth/me/notification-preferences', [
        'prefs' => [
            'new_lead' => 'true',  // строка вместо объекта
        ],
    ])->assertStatus(422);
});

test('PATCH: bool-значения каналов кастятся', function () {
    $response = $this->patchJson('/api/auth/me/notification-preferences', [
        'prefs' => [
            'new_lead' => ['email' => 1, 'inapp' => 0, 'push' => '1'],
        ],
    ]);

    $response->assertOk();
    $prefs = $response->json('user.notification_preferences.new_lead');
    expect($prefs['email'])->toBeTrue();
    expect($prefs['inapp'])->toBeFalse();
    expect($prefs['push'])->toBeTrue();
});

test('PATCH полностью замещает prefs (не merge): ранее сохранённые отсутствующие events исчезают', function () {
    // Дано: user имеет полный default-набор (schema-default 8 events).
    $this->user->update(['notification_preferences' => [
        'new_lead' => ['email' => true],
        'reminder' => ['email' => true],
        'low_balance' => ['email' => true],
    ]]);

    // Update только new_lead — остальные пропадают (replace-семантика).
    $response = $this->patchJson('/api/auth/me/notification-preferences', [
        'prefs' => ['new_lead' => ['email' => false]],
    ]);

    $response->assertOk();
    $prefs = $response->json('user.notification_preferences');
    expect($prefs)->toHaveKey('new_lead');
    expect($prefs)->not->toHaveKey('reminder');
    expect($prefs)->not->toHaveKey('low_balance');
});
