<?php

declare(strict_types=1);

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

uses(DatabaseTransactions::class);

function makeBalanceTenant(string $balanceRub): Tenant
{
    return Tenant::factory()->create(['balance_rub' => $balanceRub]);
}

it('sets exact balance and records signed manual_adjustment delta', function () {
    $tenant = makeBalanceTenant('1000.00');

    $resp = $this->patchJson("/api/admin/tenants/{$tenant->id}/balance", [
        'balance_rub' => '2500.00',
        'reason' => 'Коррекция тестового баланса',
    ]);

    $resp->assertOk()
        ->assertJsonPath('balance_rub', '2500.00')
        ->assertJsonPath('delta', '1500.00');

    $tenant->refresh();
    expect((string) $tenant->balance_rub)->toBe('2500.00');

    $tx = BalanceTransaction::where('tenant_id', $tenant->id)
        ->where('type', BalanceTransaction::TYPE_MANUAL_ADJUSTMENT)
        ->latest('id')->first();
    expect($tx)->not->toBeNull();
    expect((string) $tx->amount_rub)->toBe('1500.00');
    expect((string) $tx->balance_rub_after)->toBe('2500.00');
    expect($tx->amount_leads)->toBeNull();
    expect($tx->description)->toBe('Коррекция тестового баланса');
});

it('records negative delta when lowering balance', function () {
    $tenant = makeBalanceTenant('1000.00');

    $resp = $this->patchJson("/api/admin/tenants/{$tenant->id}/balance", [
        'balance_rub' => '300.00',
    ]);

    $resp->assertOk()->assertJsonPath('delta', '-700.00');

    $tx = BalanceTransaction::where('tenant_id', $tenant->id)
        ->where('type', BalanceTransaction::TYPE_MANUAL_ADJUSTMENT)
        ->latest('id')->first();
    expect((string) $tx->amount_rub)->toBe('-700.00');
    expect($tx->description)->toBe('Ручная корректировка баланса (админ)');
});

it('accepts negative target balance (debt correction)', function () {
    $tenant = makeBalanceTenant('0.00');

    $this->patchJson("/api/admin/tenants/{$tenant->id}/balance", [
        'balance_rub' => '-500.00',
    ])->assertOk()->assertJsonPath('balance_rub', '-500.00');

    expect((string) $tenant->fresh()->balance_rub)->toBe('-500.00');
});

it('rejects no-op (target equals current) with 422', function () {
    $tenant = makeBalanceTenant('1000.00');

    $this->patchJson("/api/admin/tenants/{$tenant->id}/balance", [
        'balance_rub' => '1000.00',
    ])->assertStatus(422);
});

it('rejects malformed balance_rub with 422', function () {
    $tenant = makeBalanceTenant('1000.00');

    $this->patchJson("/api/admin/tenants/{$tenant->id}/balance", [
        'balance_rub' => '10.123',
    ])->assertStatus(422);

    $this->patchJson("/api/admin/tenants/{$tenant->id}/balance", [
        'balance_rub' => 'abc',
    ])->assertStatus(422);
});

it('returns 404 for missing or soft-deleted tenant', function () {
    $this->patchJson('/api/admin/tenants/99999999/balance', [
        'balance_rub' => '100.00',
    ])->assertStatus(404);

    $tenant = makeBalanceTenant('100.00');
    $tenant->delete();
    $this->patchJson("/api/admin/tenants/{$tenant->id}/balance", [
        'balance_rub' => '200.00',
    ])->assertStatus(404);
});
