<?php

use App\Enums\CashTransactionType;
use App\Models\CashAccount;
use App\Models\CashTransaction;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Inertia\Testing\AssertableInertia as Assert;

uses(RefreshDatabase::class);

/*
|--------------------------------------------------------------------------
| AUTHENTICATION
|--------------------------------------------------------------------------
*/

test('guests are redirected to the login page', function () {
    $response = $this->get(route('admin.finance.cash-accounts.index'));
    $response->assertRedirect(route('login'));
});

test('authenticated users can visit the cash account index page', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->get(route('admin.finance.cash-accounts.index'));
    $response->assertOk();
});

/*
|--------------------------------------------------------------------------
| INDEX PAGE
|--------------------------------------------------------------------------
*/

test('cash account index page displays cash account and transactions', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 500000]);

    $response = $this->get(route('admin.finance.cash-accounts.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/finance/cash-account/index')
        ->has('cashAccount')
        ->has('transactions.data')
        ->where('transactions.current_page', 1)
        ->where('transactions.per_page', 25)
    );
});

test('index page works when no cash account exists', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->get(route('admin.finance.cash-accounts.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/finance/cash-account/index')
        ->has('transactions.data', 0)
        ->where('transactions.total', 0)
        ->where('transactions.current_page', 1)
        ->where('transactions.per_page', 25)
    );
});

test('index page displays correct balance', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 750000]);

    $response = $this->get(route('admin.finance.cash-accounts.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/finance/cash-account/index')
        ->where('cashAccount.balance', 750000)
    );
});

/*
|--------------------------------------------------------------------------
| FILTER - TRANSACTION TYPE
|--------------------------------------------------------------------------
*/

test('index can filter by type deposit', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 200000]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 100000,
        'balance_after' => 100000,
        'description' => 'Deposit pertama',
    ]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 50000,
        'balance_after' => 200000,
        'description' => 'Withdrawal pertama',
    ]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 100000,
        'balance_after' => 200000,
        'description' => 'Deposit kedua',
    ]);

    $response = $this->get(route('admin.finance.cash-accounts.index', ['type' => 'deposit']));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/finance/cash-account/index')
        ->has('transactions.data', 2)
        ->where('transactions.total', 2)
        ->where('transactions.current_page', 1)
        ->where('transactions.per_page', 25)
    );
});

test('index can filter by type withdrawal', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 100000,
        'balance_after' => 100000,
        'description' => 'Deposit',
    ]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'Withdrawal pertama',
    ]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 20000,
        'balance_after' => 100000,
        'description' => 'Withdrawal kedua',
    ]);

    $response = $this->get(route('admin.finance.cash-accounts.index', ['type' => 'withdrawal']));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/finance/cash-account/index')
        ->has('transactions.data', 2)
        ->where('transactions.total', 2)
        ->where('transactions.current_page', 1)
        ->where('transactions.per_page', 25)
    );
});

test('index can filter by type expense', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 100000,
        'balance_after' => 100000,
        'description' => 'Deposit',
    ]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::EXPENSE,
        'amount' => 25000,
        'balance_after' => 100000,
        'description' => 'Pengeluaran',
    ]);

    $response = $this->get(route('admin.finance.cash-accounts.index', ['type' => 'expense']));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/finance/cash-account/index')
        ->has('transactions.data', 1)
        ->where('transactions.total', 1)
        ->where('transactions.current_page', 1)
        ->where('transactions.per_page', 25)
    );
});

test('index can filter by type transfer', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 100000,
        'balance_after' => 100000,
        'description' => 'Deposit',
    ]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::TRANSFER,
        'amount' => 50000,
        'balance_after' => 100000,
        'description' => 'Transfer',
    ]);

    $response = $this->get(route('admin.finance.cash-accounts.index', ['type' => 'transfer']));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/finance/cash-account/index')
        ->has('transactions.data', 1)
        ->where('transactions.total', 1)
        ->where('transactions.current_page', 1)
        ->where('transactions.per_page', 25)
    );
});

test('index without type filter shows all transactions', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 200000]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 100000,
        'balance_after' => 100000,
        'description' => 'Deposit',
    ]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 50000,
        'balance_after' => 200000,
        'description' => 'Withdrawal',
    ]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::EXPENSE,
        'amount' => 30000,
        'balance_after' => 200000,
        'description' => 'Expense',
    ]);

    $response = $this->get(route('admin.finance.cash-accounts.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/finance/cash-account/index')
        ->has('transactions.data', 3)
        ->where('transactions.total', 3)
        ->where('transactions.current_page', 1)
        ->where('transactions.per_page', 25)
    );
});

test('index passes type filter to view', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->get(route('admin.finance.cash-accounts.index', ['type' => 'deposit']));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->where('filters.type', 'deposit')
    );
});

test('index passes empty filters when no type specified', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->get(route('admin.finance.cash-accounts.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->where('filters', [])
    );
});

test('index with invalid type filter shows no transactions', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 100000,
        'balance_after' => 100000,
        'description' => 'Deposit',
    ]);

    $response = $this->get(route('admin.finance.cash-accounts.index', ['type' => 'invalid_type']));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/finance/cash-account/index')
        ->has('transactions.data', 0)
        ->where('transactions.total', 0)
        ->where('transactions.current_page', 1)
        ->where('transactions.per_page', 25)
    );
});

/*
|--------------------------------------------------------------------------
| DEPOSIT
|--------------------------------------------------------------------------
*/

test('deposit can be made', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Deposit test',
        'receipt_key' => 'cash-transaction/deposit-001.jpg',
    ]);

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.finance.cash-accounts.index'));

    expect(CashAccount::first()->balance)->toBe(150000);
});

test('deposit creates a transaction record', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Deposit test',
        'receipt_key' => 'cash-transaction/deposit-001.jpg',
    ]);

    $this->assertDatabaseCount('cash_transactions', 1);
    $this->assertDatabaseHas('cash_transactions', [
        'type' => CashTransactionType::DEPOSIT->value,
        'amount' => 50000,
        'balance_after' => 150000,
        'description' => 'Deposit test',
    ]);
});

test('deposit sets created_by_id to authenticated user', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Deposit test',
        'receipt_key' => 'cash-transaction/deposit-001.jpg',
    ]);

    $this->assertDatabaseHas('cash_transactions', [
        'created_by_id' => $user->id,
    ]);
});

test('deposit amount is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => '',
        'description' => 'Test',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('deposit amount must be integer', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 'abc',
        'description' => 'Test',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('deposit amount must be at least 1', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 0,
        'description' => 'Test',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('deposit amount of exactly 1 is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 1,
        'description' => 'Minimum deposit',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(1);
});

test('deposit description is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => '',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('description');
});

test('deposit description must not exceed 100 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => str_repeat('a', 101),
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('description');
});

test('deposit description exactly 100 characters is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => str_repeat('a', 100),
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasNoErrors();
});

test('deposit with formatted amount containing dots is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => '50.000',
        'description' => 'Formatted deposit',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(50000);
});

test('deposit with large amount is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 1000000000,
        'description' => 'Large deposit',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(1000000000);
});

test('deposit with negative amount is rejected', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => -50000,
        'description' => 'Negative deposit',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('multiple deposits accumulate balance correctly', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 100000,
        'description' => 'First deposit',
        'receipt_key' => 'cash-transaction/receipt1.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 200000,
        'description' => 'Second deposit',
        'receipt_key' => 'cash-transaction/receipt2.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 300000,
        'description' => 'Third deposit',
        'receipt_key' => 'cash-transaction/receipt3.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(600000);
    $this->assertDatabaseCount('cash_transactions', 3);
});

test('deposit with zero balance account works', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'First deposit',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(50000);
});

test('deposit flashes success toast', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Deposit toast test',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertRedirect();
});

test('deposit receipt_key is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Test',
    ]);

    $response->assertSessionHasErrors('receipt_key');
});

test('deposit receipt_key max length is 500', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Test',
        'receipt_key' => str_repeat('a', 501),
    ]);

    $response->assertSessionHasErrors('receipt_key');
});

test('deposit receipt_key exactly 500 characters is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Test',
        'receipt_key' => str_repeat('a', 500),
    ]);

    $response->assertSessionHasNoErrors();
});

/*
|--------------------------------------------------------------------------
| WITHDRAWAL
|--------------------------------------------------------------------------
*/

test('withdrawal can be made', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 30000,
        'description' => 'Withdrawal test',
        'receipt_key' => 'cash-transaction/withdrawal-001.jpg',
    ]);

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.finance.cash-accounts.index'));

    expect(CashAccount::first()->balance)->toBe(70000);
});

test('withdrawal creates a transaction record', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 30000,
        'description' => 'Withdrawal test',
        'receipt_key' => 'cash-transaction/withdrawal-001.jpg',
    ]);

    $this->assertDatabaseCount('cash_transactions', 1);
    $this->assertDatabaseHas('cash_transactions', [
        'type' => CashTransactionType::WITHDRAWAL->value,
        'amount' => 30000,
        'balance_after' => 70000,
        'description' => 'Withdrawal test',
    ]);
});

test('withdrawal sets created_by_id to authenticated user', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 30000,
        'description' => 'Withdrawal test',
        'receipt_key' => 'cash-transaction/withdrawal-001.jpg',
    ]);

    $this->assertDatabaseHas('cash_transactions', [
        'created_by_id' => $user->id,
    ]);
});

test('withdrawal fails when balance is insufficient', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 50000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 100000,
        'description' => 'Withdrawal test',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    // Controller catches ValidationException and flashes toast error
    $response->assertRedirect();
    expect(CashAccount::first()->balance)->toBe(50000);
});

test('withdrawal of exact balance succeeds', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 50000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => 'Withdrawal exact balance',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(0);
});

test('withdrawal of entire balance leaves zero', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 100000,
        'description' => 'Withdraw all',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(0);
});

test('withdrawal amount is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => '',
        'description' => 'Test',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('withdrawal amount must be integer', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 'abc',
        'description' => 'Test',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('withdrawal amount must be at least 1', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 0,
        'description' => 'Test',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('withdrawal description is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => '',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasErrors('description');
});

test('withdrawal description must not exceed 100 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => str_repeat('a', 101),
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasErrors('description');
});

test('withdrawal with formatted amount containing dots is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => '50.000',
        'description' => 'Formatted withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(50000);
});

test('withdrawal with negative amount is rejected', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => -50000,
        'description' => 'Negative withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('multiple withdrawals decrease balance correctly', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 1000000]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 100000,
        'description' => 'First withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal1.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 200000,
        'description' => 'Second withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal2.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 300000,
        'description' => 'Third withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal3.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(400000);
    $this->assertDatabaseCount('cash_transactions', 3);
});

test('withdrawal with insufficient balance does not create transaction', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 50000]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 100000,
        'description' => 'Should fail',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $this->assertDatabaseCount('cash_transactions', 0);
});

test('withdrawal receipt_key is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => 'Test',
    ]);

    $response->assertSessionHasErrors('receipt_key');
});

test('withdrawal receipt_key max length is 500', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => 'Test',
        'receipt_key' => str_repeat('a', 501),
    ]);

    $response->assertSessionHasErrors('receipt_key');
});

test('withdrawal receipt_key exactly 500 characters is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => 'Test',
        'receipt_key' => str_repeat('a', 500),
    ]);

    $response->assertSessionHasNoErrors();
});

/*
|--------------------------------------------------------------------------
| MIXED DEPOSIT AND WITHDRAWAL
|--------------------------------------------------------------------------
*/

test('deposit and withdrawal maintain correct balance sequence', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 500000,
        'description' => 'Initial deposit',
        'receipt_key' => 'cash-transaction/deposit1.jpg',
    ]);
    expect(CashAccount::first()->balance)->toBe(500000);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 200000,
        'description' => 'First withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal1.jpg',
    ]);
    expect(CashAccount::first()->balance)->toBe(300000);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 100000,
        'description' => 'Second deposit',
        'receipt_key' => 'cash-transaction/deposit2.jpg',
    ]);
    expect(CashAccount::first()->balance)->toBe(400000);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 400000,
        'description' => 'Final withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal2.jpg',
    ]);
    expect(CashAccount::first()->balance)->toBe(0);

    $this->assertDatabaseCount('cash_transactions', 4);
});

test('cannot withdraw more than available balance after mixed transactions', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 100000,
        'description' => 'Deposit',
        'receipt_key' => 'cash-transaction/deposit.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 80000,
        'description' => 'Withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(20000);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 30000,
        'description' => 'Should fail',
        'receipt_key' => 'cash-transaction/withdrawal2.jpg',
    ]);

    $response->assertRedirect();
    expect(CashAccount::first()->balance)->toBe(20000);
    $this->assertDatabaseCount('cash_transactions', 2);
});

/*
|--------------------------------------------------------------------------
| UPDATE TRANSACTION
|--------------------------------------------------------------------------
*/

test('deposit transaction can be updated', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
        'balance_after' => 100000,
        'description' => 'Original deposit',
    ]);

    // Update deposit from 50,000 to 75,000
    // difference = 75,000 - 50,000 = 25,000
    // newBalance = 100,000 + 25,000 = 125,000
    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 75000,
        'description' => 'Updated deposit',
        'receipt_key' => 'cash-transaction/deposit-updated.jpg',
    ]);

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.finance.cash-accounts.index'));

    expect(CashAccount::first()->balance)->toBe(125000);

    $transaction->refresh();
    expect($transaction->amount)->toBe(75000);
    expect($transaction->description)->toBe('Updated deposit');
});

test('withdrawal transaction can be updated', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'Original withdrawal',
    ]);

    // Update withdrawal from 30,000 to 20,000
    // difference = 30,000 - 20,000 = 10,000 (positive, reducing withdrawal)
    // newBalance = 100,000 + 10,000 = 110,000
    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 20000,
        'description' => 'Updated withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal-updated.jpg',
    ]);

    $response->assertSessionHasNoErrors();

    expect(CashAccount::first()->balance)->toBe(110000);

    $transaction->refresh();
    expect($transaction->amount)->toBe(20000);
    expect($transaction->description)->toBe('Updated withdrawal');
});

test('expense transaction cannot be updated', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::EXPENSE,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'Expense',
    ]);

    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 20000,
        'description' => 'Updated expense',
        'receipt_key' => 'cash-transaction/expense-updated.jpg',
    ]);

    $response->assertRedirect();
    expect(CashAccount::first()->balance)->toBe(100000);
});

test('transfer transaction cannot be updated', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::TRANSFER,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'Transfer',
    ]);

    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 20000,
        'description' => 'Updated transfer',
        'receipt_key' => 'cash-transaction/transfer-updated.jpg',
    ]);

    $response->assertRedirect();
    expect(CashAccount::first()->balance)->toBe(100000);
});

test('updating deposit to higher amount increases balance', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    // Update from 50,000 to 80,000
    // difference = 80,000 - 50,000 = 30,000
    // newBalance = 100,000 + 30,000 = 130,000
    $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 80000,
        'description' => 'Increased',
        'receipt_key' => 'cash-transaction/deposit-increased.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(130000);
});

test('updating deposit to lower amount decreases balance', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    // Update from 50,000 to 20,000
    // difference = 20,000 - 50,000 = -30,000
    // newBalance = 100,000 + (-30,000) = 70,000
    $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 20000,
        'description' => 'Decreased',
        'receipt_key' => 'cash-transaction/deposit-decreased.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(70000);
});

test('updating withdrawal to higher amount decreases balance further', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    // Update from 30,000 to 50,000
    // difference = 30,000 - 50,000 = -20,000
    // newBalance = 100,000 + (-20,000) = 80,000
    $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 50000,
        'description' => 'Increased withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal-increased.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(80000);
});

test('updating withdrawal to lower amount increases balance', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    // Update from 30,000 to 10,000
    // difference = 30,000 - 10,000 = 20,000
    // newBalance = 100,000 + 20,000 = 120,000
    $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 10000,
        'description' => 'Decreased withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal-decreased.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(120000);
});

test('updating deposit to zero amount is rejected', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 0,
        'description' => 'Zero amount',
        'receipt_key' => 'cash-transaction/deposit.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
    expect(CashAccount::first()->balance)->toBe(100000);
});

test('updating transaction with formatted amount is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    // Update from 50,000 to 75,000
    // difference = 25,000
    // newBalance = 125,000
    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => '75.000',
        'description' => 'Formatted amount',
        'receipt_key' => 'cash-transaction/deposit.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(125000);
});

test('transaction update requires receipt_key', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 75000,
        'description' => 'Updated',
    ]);

    $response->assertSessionHasErrors('receipt_key');
});

/*
|--------------------------------------------------------------------------
| DELETE TRANSACTION
|--------------------------------------------------------------------------
*/

test('deposit transaction can be deleted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
        'balance_after' => 100000,
        'description' => 'To be deleted',
    ]);

    // Delete deposit: newBalance = 100,000 - 50,000 = 50,000
    $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction));

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.finance.cash-accounts.index'));

    expect(CashAccount::first()->balance)->toBe(50000);
    $this->assertSoftDeleted('cash_transactions', ['id' => $transaction->id]);
});

test('withdrawal transaction can be deleted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'To be deleted',
    ]);

    // Delete withdrawal: newBalance = 100,000 + 30,000 = 130,000
    $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction));

    $response->assertSessionHasNoErrors();

    expect(CashAccount::first()->balance)->toBe(130000);
    $this->assertSoftDeleted('cash_transactions', ['id' => $transaction->id]);
});

test('expense transaction cannot be deleted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::EXPENSE,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'Expense',
    ]);

    $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction));

    $response->assertRedirect();
    expect(CashAccount::first()->balance)->toBe(100000);
});

test('transfer transaction cannot be deleted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::TRANSFER,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'Transfer',
    ]);

    $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction));

    $response->assertRedirect();
    expect(CashAccount::first()->balance)->toBe(100000);
});

test('deleting deposit reduces balance correctly', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    // Start with 0 balance, make two deposits via API to get correct balance
    $cashAccount = CashAccount::factory()->create(['balance' => 0]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 100000,
        'description' => 'Deposit 1',
        'receipt_key' => 'cash-transaction/deposit1.jpg',
    ]);
    $t1 = CashTransaction::latest()->first();

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Deposit 2',
        'receipt_key' => 'cash-transaction/deposit2.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(150000);

    // Delete first deposit: newBalance = 150,000 - 100,000 = 50,000
    $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t1));

    expect(CashAccount::first()->balance)->toBe(50000);
});

test('deleting withdrawal increases balance correctly', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    // Start with 200,000, make two withdrawals via API
    $cashAccount = CashAccount::factory()->create(['balance' => 200000]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => 'Withdrawal 1',
        'receipt_key' => 'cash-transaction/withdrawal1.jpg',
    ]);
    $t1 = CashTransaction::latest()->first();

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 30000,
        'description' => 'Withdrawal 2',
        'receipt_key' => 'cash-transaction/withdrawal2.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(120000);

    // Delete first withdrawal: newBalance = 120,000 + 50,000 = 170,000
    $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t1));

    expect(CashAccount::first()->balance)->toBe(170000);
});

test('deleting deposit that would cause negative balance is rejected', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 50000]);

    // Deposit 50,000 via API (balance becomes 100,000)
    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Deposit',
        'receipt_key' => 'cash-transaction/deposit.jpg',
    ]);
    $deposit = CashTransaction::latest()->first();

    // Withdraw 80,000 (balance becomes 20,000)
    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 80000,
        'description' => 'Withdrawal',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(20000);

    // Try to delete the deposit: newBalance = 20,000 - 50,000 = -30,000 (rejected)
    $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $deposit));

    $response->assertRedirect();
    expect(CashAccount::first()->balance)->toBe(20000);
});

test('multiple transactions can be deleted sequentially', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 0]);

    // Create transactions directly with known types
    $t1 = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 100000,
        'balance_after' => 100000,
        'description' => 'First deposit',
    ]);

    $t2 = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
        'balance_after' => 150000,
        'description' => 'Second deposit',
    ]);

    $t3 = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 30000,
        'balance_after' => 120000,
        'description' => 'Withdrawal',
    ]);

    // Manually set balance to 120,000 (simulating what would happen)
    $cashAccount->update(['balance' => 120000]);
    expect(CashAccount::first()->balance)->toBe(120000);

    // Delete withdrawal first: 120,000 + 30,000 = 150,000
    $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t3));
    expect(CashAccount::first()->balance)->toBe(150000);

    // Delete second deposit: 150,000 - 50,000 = 100,000
    $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t2));
    expect(CashAccount::first()->balance)->toBe(100000);

    // Delete first deposit: 100,000 - 100,000 = 0
    $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t1));
    expect(CashAccount::first()->balance)->toBe(0);
});

/*
|--------------------------------------------------------------------------
| AUTHORIZATION
|--------------------------------------------------------------------------
*/

test('guest cannot perform deposit', function () {
    CashAccount::factory()->create(['balance' => 0]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Unauthorized',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertRedirect(route('login'));
    expect(CashAccount::first()->balance)->toBe(0);
});

test('guest cannot perform withdrawal', function () {
    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => 'Unauthorized',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertRedirect(route('login'));
    expect(CashAccount::first()->balance)->toBe(100000);
});

test('guest cannot update transaction', function () {
    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);
    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
    ]);

    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 99999,
        'description' => 'Unauthorized',
    ]);

    $response->assertRedirect(route('login'));
});

test('guest cannot delete transaction', function () {
    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);
    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
    ]);

    $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction));

    $response->assertRedirect(route('login'));
    expect(CashAccount::first()->balance)->toBe(100000);
});

/*
|--------------------------------------------------------------------------
| DATA INTEGRITY
|--------------------------------------------------------------------------
*/

test('cash account has correct timestamps', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create();

    expect($cashAccount->created_at)->not->toBeNull();
    expect($cashAccount->updated_at)->not->toBeNull();
});

test('cash transaction has correct timestamps', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create();

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
    ]);

    expect($transaction->created_at)->not->toBeNull();
    expect($transaction->updated_at)->not->toBeNull();
});

test('cash account balance is cast to integer', function () {
    $cashAccount = CashAccount::factory()->create(['balance' => 500000]);
    expect($cashAccount->balance)->toBeInt();
});

test('cash transaction amount is cast to integer', function () {
    $cashAccount = CashAccount::factory()->create();
    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'amount' => 50000,
    ]);
    expect($transaction->amount)->toBeInt();
});

test('cash transaction balance_after is cast to integer', function () {
    $cashAccount = CashAccount::factory()->create();
    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'balance_after' => 100000,
    ]);
    expect($transaction->balance_after)->toBeInt();
});

test('cash transaction type is cast to enum', function () {
    $cashAccount = CashAccount::factory()->create();
    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'type' => CashTransactionType::DEPOSIT,
    ]);
    expect($transaction->type)->toBeInstanceOf(CashTransactionType::class);
});

test('cash account balance defaults to zero', function () {
    $cashAccount = CashAccount::factory()->create(['balance' => 0]);
    expect($cashAccount->balance)->toBe(0);
});

test('cash transaction has correct type values', function () {
    expect(CashTransactionType::DEPOSIT->value)->toBe('deposit');
    expect(CashTransactionType::WITHDRAWAL->value)->toBe('withdrawal');
    expect(CashTransactionType::EXPENSE->value)->toBe('expense');
    expect(CashTransactionType::TRANSFER->value)->toBe('transfer');
});

/*
|--------------------------------------------------------------------------
| SOFT DELETE
|--------------------------------------------------------------------------
*/

test('cash transaction is soft deleted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
    ]);

    $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction));

    $this->assertSoftDeleted('cash_transactions', ['id' => $transaction->id]);
});

test('soft deleted transaction still exists in database', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 50000,
    ]);

    $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction));

    $this->assertDatabaseHas('cash_transactions', ['id' => $transaction->id]);
    $this->assertSoftDeleted('cash_transactions', ['id' => $transaction->id]);
});

/*
|--------------------------------------------------------------------------
| REALISTIC USER SCENARIOS
|--------------------------------------------------------------------------
*/

test('user makes deposit then withdrawal in sequence', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 500000,
        'description' => 'Modal usaha',
        'receipt_key' => 'cash-transaction/deposit.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 100000,
        'description' => 'Belanja inventory',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(400000);
    $this->assertDatabaseCount('cash_transactions', 2);
});

test('user makes multiple deposits throughout the day', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 200000,
        'description' => 'Penjualan pagi',
        'receipt_key' => 'cash-transaction/deposit1.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 350000,
        'description' => 'Penjualan siang',
        'receipt_key' => 'cash-transaction/deposit2.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 150000,
        'description' => 'Penjualan sore',
        'receipt_key' => 'cash-transaction/deposit3.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(700000);
    $this->assertDatabaseCount('cash_transactions', 3);
});

test('user makes withdrawal for expenses', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 1000000]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => 'Bayar listrik',
        'receipt_key' => 'cash-transaction/withdrawal1.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 30000,
        'description' => 'Bayar air',
        'receipt_key' => 'cash-transaction/withdrawal2.jpg',
    ]);

    $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 200000,
        'description' => 'Gaji karyawan',
        'receipt_key' => 'cash-transaction/withdrawal3.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(720000);
});

test('user edits deposit description', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::DEPOSIT,
        'amount' => 100000,
        'balance_after' => 100000,
        'description' => 'Penjualan',
    ]);

    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 100000,
        'description' => 'Penjualan produk A',
        'receipt_key' => 'cash-transaction/deposit.jpg',
    ]);

    $response->assertSessionHasNoErrors();

    $transaction->refresh();
    expect($transaction->description)->toBe('Penjualan produk A');
    expect($transaction->amount)->toBe(100000);
    expect(CashAccount::first()->balance)->toBe(100000);
});

test('user deletes wrong deposit and re-enters correct amount', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 0]);

    // Wrong deposit via API
    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 100000,
        'description' => 'Wrong amount',
        'receipt_key' => 'cash-transaction/deposit.jpg',
    ]);
    $wrongDeposit = CashTransaction::where('cash_account_id', $cashAccount->id)->first();

    expect(CashAccount::first()->balance)->toBe(100000);

    // Delete wrong deposit: 100,000 - 100,000 = 0
    $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $wrongDeposit));
    expect(CashAccount::first()->balance)->toBe(0);

    // Re-enter correct deposit
    $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 150000,
        'description' => 'Correct amount',
        'receipt_key' => 'cash-transaction/deposit-correct.jpg',
    ]);

    expect(CashAccount::first()->balance)->toBe(150000);
    // Old transaction is soft deleted, new one created
    $this->assertDatabaseCount('cash_transactions', 2);
});

test('user attempts withdrawal with exact balance', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 100000,
        'description' => 'Withdraw all',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(0);
});

test('user attempts withdrawal with 1 more than balance', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 100001,
        'description' => 'Over balance',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertRedirect();
    expect(CashAccount::first()->balance)->toBe(100000);
});

test('user rapidly makes multiple deposits', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    for ($i = 0; $i < 5; $i++) {
        $this->post(route('admin.finance.cash-accounts.deposit'), [
            'amount' => 100000,
            'description' => "Deposit {$i}",
            'receipt_key' => "cash-transaction/deposit{$i}.jpg",
        ]);
    }

    expect(CashAccount::first()->balance)->toBe(500000);
    $this->assertDatabaseCount('cash_transactions', 5);
});

test('user edits withdrawal amount to reduce it', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 50000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    // Reduce withdrawal from 50,000 to 20,000
    // difference = 50,000 - 20,000 = 30,000
    // newBalance = 100,000 + 30,000 = 130,000
    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 20000,
        'description' => 'Reduced',
        'receipt_key' => 'cash-transaction/withdrawal-reduced.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(130000);
});

test('user edits withdrawal amount to increase it', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 20000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    // Increase withdrawal from 20,000 to 60,000
    // difference = 20,000 - 60,000 = -40,000
    // newBalance = 100,000 + (-40,000) = 60,000
    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 60000,
        'description' => 'Increased',
        'receipt_key' => 'cash-transaction/withdrawal-increased.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(60000);
});

test('user cannot edit withdrawal to exceed remaining balance', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);

    $transaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => CashTransactionType::WITHDRAWAL,
        'amount' => 30000,
        'balance_after' => 100000,
        'description' => 'Original',
    ]);

    expect(CashAccount::first()->balance)->toBe(100000);

    // Increase withdrawal from 30,000 to 200,000
    // difference = 30,000 - 200,000 = -170,000
    // newBalance = 100,000 + (-170,000) = -70,000 (insufficient)
    $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [
        'amount' => 200000,
        'description' => 'Way too much',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertRedirect();
    expect(CashAccount::first()->balance)->toBe(100000);
});

test('deposit with description containing special characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'description' => 'Deposit dari PT. Maju Jaya & Co.',
        'receipt_key' => 'cash-transaction/deposit.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseHas('cash_transactions', [
        'description' => 'Deposit dari PT. Maju Jaya & Co.',
    ]);
});

test('withdrawal with description containing unicode characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 100000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'description' => 'Pembayaran gaji karyawan',
        'receipt_key' => 'cash-transaction/withdrawal.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseHas('cash_transactions', [
        'description' => 'Pembayaran gaji karyawan',
    ]);
});

test('deposit without description fails validation', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => 50000,
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('description');
});

test('withdrawal without description fails validation', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => 50000,
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('description');
});

test('deposit with empty string amount fails validation', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => '',
        'description' => 'Test',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('withdrawal with empty string amount fails validation', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create();

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => '',
        'description' => 'Test',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasErrors('amount');
});

test('deposit with float amount is parsed correctly', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 0]);

    $response = $this->post(route('admin.finance.cash-accounts.deposit'), [
        'amount' => '100.500',
        'description' => 'Float amount',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(100500);
});

test('withdrawal with float amount is parsed correctly', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    CashAccount::factory()->create(['balance' => 1000000]);

    $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [
        'amount' => '250.000',
        'description' => 'Float amount',
        'receipt_key' => 'cash-transaction/receipt.jpg',
    ]);

    $response->assertSessionHasNoErrors();
    expect(CashAccount::first()->balance)->toBe(750000);
});
