<?php

declare(strict_types=1);

use App\Models\Reminder;
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Carbon;

uses(DatabaseTransactions::class);

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

function makeReminder(int $tenantId, int $userId, array $overrides = []): Reminder
{
    return Reminder::create(array_merge([
        'tenant_id' => $tenantId,
        'deal_id' => 42,
        'text' => 'Перезвонить клиенту',
        'remind_at' => Carbon::now()->addHour(),
        'created_by' => $userId,
        'is_sent' => false,
    ], $overrides));
}

test('GET /api/reminders: 401 без auth', function () {
    auth()->logout();
    $this->getJson('/api/reminders')->assertStatus(401);
});

test('GET /api/reminders: пустой', function () {
    $response = $this->getJson('/api/reminders');
    $response->assertOk();
    expect($response->json('items'))->toBe([]);
    expect($response->json('counts.active'))->toBe(0);
});

test('GET /api/reminders: возвращает только свои', function () {
    $otherTenant = Tenant::factory()->create();
    $otherUser = User::factory()->create(['tenant_id' => $otherTenant->id]);
    makeReminder($this->tenant->id, $this->user->id);
    makeReminder($otherTenant->id, $otherUser->id);

    $response = $this->getJson('/api/reminders');
    $response->assertOk();
    expect($response->json('items'))->toHaveCount(1);
});

test('GET /api/reminders?filter=overdue: возвращает только просроченные', function () {
    makeReminder($this->tenant->id, $this->user->id, ['remind_at' => Carbon::now()->subDays(2)]);  // overdue
    makeReminder($this->tenant->id, $this->user->id, ['remind_at' => Carbon::now()->addHour()]);   // today
    makeReminder($this->tenant->id, $this->user->id, ['remind_at' => Carbon::now()->addDays(5)]);  // upcoming

    $response = $this->getJson('/api/reminders?filter=overdue');
    expect($response->json('items'))->toHaveCount(1);
});

test('GET /api/reminders?filter=today: возвращает в пределах ±1д', function () {
    makeReminder($this->tenant->id, $this->user->id, ['remind_at' => Carbon::now()->addHours(3)]);
    makeReminder($this->tenant->id, $this->user->id, ['remind_at' => Carbon::now()->addDays(5)]);  // upcoming

    $response = $this->getJson('/api/reminders?filter=today');
    expect($response->json('items'))->toHaveCount(1);
});

test('GET /api/reminders?filter=completed: возвращает выполненные', function () {
    makeReminder($this->tenant->id, $this->user->id, ['completed_at' => Carbon::now()]);
    makeReminder($this->tenant->id, $this->user->id, ['completed_at' => null]);

    $response = $this->getJson('/api/reminders?filter=completed');
    expect($response->json('items'))->toHaveCount(1);
});

test('GET /api/reminders: counts отдельно для каждого фильтра', function () {
    makeReminder($this->tenant->id, $this->user->id, ['remind_at' => Carbon::now()->subDays(2)]);
    makeReminder($this->tenant->id, $this->user->id, ['remind_at' => Carbon::now()->addHour()]);
    makeReminder($this->tenant->id, $this->user->id, ['remind_at' => Carbon::now()->addDays(3)]);

    $response = $this->getJson('/api/reminders');
    expect($response->json('counts.active'))->toBe(3);
    expect($response->json('counts.overdue'))->toBe(1);
    expect($response->json('counts.today'))->toBe(1);
    expect($response->json('counts.upcoming'))->toBe(1);
});

test('GET /api/reminders?deal_id=42: фильтр по сделке', function () {
    makeReminder($this->tenant->id, $this->user->id, ['deal_id' => 42]);
    makeReminder($this->tenant->id, $this->user->id, ['deal_id' => 43]);

    $response = $this->getJson('/api/reminders?deal_id=42');
    expect($response->json('items'))->toHaveCount(1);
    expect($response->json('items.0.deal_id'))->toBe(42);
});

test('POST /api/reminders: создаёт', function () {
    $response = $this->postJson('/api/reminders', [
        'deal_id' => 100,
        'text' => 'Перезвонить через час',
        'remind_at' => Carbon::now()->addHour()->toIso8601String(),
    ]);

    $response->assertStatus(201);
    expect($response->json('reminder.deal_id'))->toBe(100);
    expect($response->json('reminder.text'))->toBe('Перезвонить через час');
    expect($response->json('reminder.is_sent'))->toBeFalse();
    expect($response->json('reminder.created_by'))->toBe($this->user->id);

    expect(Reminder::query()->count())->toBe(1);
});

test('POST /api/reminders: 422 без deal_id', function () {
    $this->postJson('/api/reminders', [
        'remind_at' => Carbon::now()->addHour()->toIso8601String(),
    ])->assertStatus(422);
});

test('POST /api/reminders: 422 без remind_at', function () {
    $this->postJson('/api/reminders', [
        'deal_id' => 100,
    ])->assertStatus(422);
});

test('POST /api/reminders: assignee_id чужого тенанта → 422', function () {
    $other = User::factory()->create();  // другой тенант
    $this->postJson('/api/reminders', [
        'deal_id' => 100,
        'remind_at' => Carbon::now()->addHour()->toIso8601String(),
        'assignee_id' => $other->id,
    ])->assertStatus(422);
});

test('POST /api/reminders: assignee_id своего тенанта — ok', function () {
    $colleague = User::factory()->create(['tenant_id' => $this->tenant->id]);
    $response = $this->postJson('/api/reminders', [
        'deal_id' => 100,
        'remind_at' => Carbon::now()->addHour()->toIso8601String(),
        'assignee_id' => $colleague->id,
    ]);
    $response->assertStatus(201);
    expect($response->json('reminder.assignee_id'))->toBe($colleague->id);
});

test('PATCH /api/reminders/{id}: обновляет text', function () {
    $reminder = makeReminder($this->tenant->id, $this->user->id);
    $response = $this->patchJson("/api/reminders/{$reminder->id}", ['text' => 'Новый текст']);
    $response->assertOk();
    expect($response->json('reminder.text'))->toBe('Новый текст');
});

test('PATCH /api/reminders/{id}: смена remind_at сбрасывает is_sent', function () {
    $reminder = makeReminder($this->tenant->id, $this->user->id, [
        'is_sent' => true,
        'sent_at' => Carbon::now()->subMinute(),
    ]);

    $response = $this->patchJson("/api/reminders/{$reminder->id}", [
        'remind_at' => Carbon::now()->addHours(3)->toIso8601String(),
    ]);

    $response->assertOk();
    expect($response->json('reminder.is_sent'))->toBeFalse();
    expect($response->json('reminder.sent_at'))->toBeNull();
});

test('PATCH /api/reminders/{id}: 404 для чужого', function () {
    $other = User::factory()->create();
    $reminder = makeReminder($other->tenant_id, $other->id);

    $this->patchJson("/api/reminders/{$reminder->id}", ['text' => 'Hack'])->assertStatus(404);
});

test('PATCH /api/reminders/{id}: 422 без полей', function () {
    $reminder = makeReminder($this->tenant->id, $this->user->id);
    $this->patchJson("/api/reminders/{$reminder->id}", [])->assertStatus(422);
});

test('POST /api/reminders/{id}/complete: ставит completed_at', function () {
    $reminder = makeReminder($this->tenant->id, $this->user->id);
    $response = $this->postJson("/api/reminders/{$reminder->id}/complete");
    $response->assertOk();
    expect($response->json('reminder.completed_at'))->not->toBeNull();
});

test('POST /api/reminders/{id}/complete: idempotent (повторный NO-OP)', function () {
    $reminder = makeReminder($this->tenant->id, $this->user->id);
    $first = $this->postJson("/api/reminders/{$reminder->id}/complete");
    $firstCompletedAt = $first->json('reminder.completed_at');

    sleep(1);
    $second = $this->postJson("/api/reminders/{$reminder->id}/complete");
    expect($second->json('reminder.completed_at'))->toBe($firstCompletedAt);  // не изменилось
});

test('DELETE /api/reminders/{id}: удаляет', function () {
    $reminder = makeReminder($this->tenant->id, $this->user->id);
    $this->deleteJson("/api/reminders/{$reminder->id}")->assertOk();
    expect(Reminder::query()->find($reminder->id))->toBeNull();
});

test('DELETE /api/reminders/{id}: 404 для чужого', function () {
    $other = User::factory()->create();
    $reminder = makeReminder($other->tenant_id, $other->id);
    $this->deleteJson("/api/reminders/{$reminder->id}")->assertStatus(404);
    expect(Reminder::query()->find($reminder->id))->not->toBeNull();
});
