<?php

declare(strict_types=1);

use App\Models\ActivityLog;
use App\Models\Deal;
use App\Models\Project;
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;

uses(DatabaseTransactions::class);

beforeEach(function () {
    $this->tenant = Tenant::factory()->create();
    $this->otherTenant = Tenant::factory()->create();

    $this->user = User::factory()->for($this->tenant)->create();
    $this->actingAs($this->user);

    DB::statement('SET app.current_tenant_id = '.$this->tenant->id);
    $this->project = Project::factory()->for($this->tenant)->create();
});

test('DELETE /api/deals 422 без обязательных полей', function () {
    $this->deleteJson('/api/deals', [])->assertStatus(422);
});

test('DELETE /api/deals 401 без auth', function () {
    auth()->logout();
    $this->deleteJson('/api/deals', ['ids' => [1]])->assertStatus(401);
});

test('DELETE /api/deals soft-удаляет сделки + пишет deal.deleted ActivityLog', function () {
    $deals = Deal::factory()->count(3)->for($this->tenant)->for($this->project)->create();

    $r = $this->deleteJson('/api/deals', [
        'ids' => $deals->pluck('id')->all(),
    ]);

    $r->assertStatus(200)->assertJson([
        'deleted' => 3,
        'requested' => 3,
    ]);

    DB::statement('SET app.current_tenant_id = '.$this->tenant->id);
    foreach ($deals as $d) {
        $row = DB::table('deals')->where('id', $d->id)->first();
        expect($row->deleted_at)->not->toBeNull();
    }

    $logs = ActivityLog::where('tenant_id', $this->tenant->id)
        ->where('event', 'deal.deleted')
        ->get();
    expect($logs)->toHaveCount(3);
    expect($logs->first()->context)->toMatchArray(['source' => 'bulk']);
});

test('DELETE /api/deals defense-in-depth не удаляет чужие сделки', function () {
    $own = Deal::factory()->for($this->tenant)->for($this->project)->create();

    DB::statement('SET app.current_tenant_id = '.$this->otherTenant->id);
    $foreignProject = Project::factory()->for($this->otherTenant)->create();
    $foreign = Deal::factory()->for($this->otherTenant)->for($foreignProject)->create();

    $r = $this->deleteJson('/api/deals', [
        'ids' => [$own->id, $foreign->id],
    ]);

    $r->assertStatus(200)->assertJson([
        'deleted' => 1,
        'requested' => 2,
    ]);

    // Свой удалён.
    DB::statement('SET app.current_tenant_id = '.$this->tenant->id);
    expect(DB::table('deals')->where('id', $own->id)->value('deleted_at'))->not->toBeNull();

    // Чужой жив.
    DB::statement('SET app.current_tenant_id = '.$this->otherTenant->id);
    expect(DB::table('deals')->where('id', $foreign->id)->value('deleted_at'))->toBeNull();
});

test('DELETE /api/deals NO-OP на уже удалённых', function () {
    $deal = Deal::factory()->for($this->tenant)->for($this->project)->create();

    // Первое удаление
    $this->deleteJson('/api/deals', [
        'ids' => [$deal->id],
    ])->assertStatus(200)->assertJson(['deleted' => 1]);

    // Повтор — уже удалена, NO-OP.
    $r = $this->deleteJson('/api/deals', [
        'ids' => [$deal->id],
    ]);
    $r->assertStatus(200)->assertJson(['deleted' => 0, 'requested' => 1]);

    // ActivityLog — только 1 запись (после первого удаления).
    DB::statement('SET app.current_tenant_id = '.$this->tenant->id);
    expect(ActivityLog::where('deal_id', $deal->id)->where('event', 'deal.deleted')->count())->toBe(1);
});

test('GET /api/deals НЕ возвращает soft-deleted сделки', function () {
    $alive = Deal::factory()->for($this->tenant)->for($this->project)->create();
    $deleted = Deal::factory()->for($this->tenant)->for($this->project)->create();

    // Удаляем одну
    $this->deleteJson('/api/deals', [
        'ids' => [$deleted->id],
    ])->assertStatus(200);

    $r = $this->getJson('/api/deals');
    $ids = collect($r->json('deals'))->pluck('id')->all();
    expect($ids)->toContain($alive->id);
    expect($ids)->not->toContain($deleted->id);
    expect($r->json('total'))->toBe(1);
});

test('GET /api/deals/{id} 404 для soft-deleted сделки', function () {
    $deal = Deal::factory()->for($this->tenant)->for($this->project)->create();

    $this->deleteJson('/api/deals', [
        'ids' => [$deal->id],
    ])->assertStatus(200);

    $this->getJson('/api/deals/'.$deal->id)
        ->assertStatus(404);
});

test('DELETE /api/deals 422 пустой массив ids', function () {
    $this->deleteJson('/api/deals', [
        'ids' => [],
    ])->assertStatus(422);
});
