<?php

use App\Models\CashAccount;
use App\Models\CashTransaction;
use App\Models\Expense;
use App\Models\User;
use Inertia\Testing\AssertableInertia as Assert;

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

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

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

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

    $cashAccount = CashAccount::factory()->create(['balance' => 1000000]);
    $cashTransaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => 'expense',
        'amount' => 50000,
    ]);
    $expense = Expense::factory()->create([
        'cash_transaction_id' => $cashTransaction->id,
        'created_by_id' => $user->id,
    ]);

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

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

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

    $response = $this->post(route('admin.finance.expenses.store'), [
        'amount' => 50000,
        'description' => 'Belanja ATK',
        'receipt_key' => 'expense/receipt-001.jpg',
    ]);

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

    $this->assertDatabaseHas('expenses', [
        'amount' => 50000,
        'description' => 'Belanja ATK',
    ]);

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

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

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

    $response = $this->post(route('admin.finance.expenses.store'), [
        'amount' => '',
        'description' => 'Test',
        'receipt_key' => 'expense/receipt.jpg',
    ]);

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

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

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

    $response = $this->post(route('admin.finance.expenses.store'), [
        'amount' => 0,
        'description' => 'Test',
        'receipt_key' => 'expense/receipt.jpg',
    ]);

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

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

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

    $response = $this->post(route('admin.finance.expenses.store'), [
        'amount' => 50000,
        'description' => '',
        'receipt_key' => 'expense/receipt.jpg',
    ]);

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

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

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

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

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

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

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

    $response = $this->post(route('admin.finance.expenses.store'), [
        'amount' => 100000,
        'description' => 'Test',
        'receipt_key' => 'expense/receipt.jpg',
    ]);

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

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

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);
    $cashTransaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => 'expense',
        'amount' => 30000,
        'balance_after' => 70000,
    ]);
    $expense = Expense::factory()->create([
        'cash_transaction_id' => $cashTransaction->id,
        'created_by_id' => $user->id,
        'amount' => 30000,
    ]);

    $response = $this->put(route('admin.finance.expenses.update', $expense), [
        'amount' => 40000,
        'description' => 'Belanja ATK Updated',
        'receipt_key' => 'expense/receipt-updated.jpg',
    ]);

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

    $expense->refresh();
    expect($expense->amount)->toBe(40000);
    expect($expense->description)->toBe('Belanja ATK Updated');
});

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

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);
    $cashTransaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => 'expense',
        'amount' => 30000,
        'balance_after' => 70000,
    ]);
    $expense = Expense::factory()->create([
        'cash_transaction_id' => $cashTransaction->id,
        'created_by_id' => $user->id,
        'amount' => 30000,
    ]);

    $response = $this->put(route('admin.finance.expenses.update', $expense), [
        'amount' => 40000,
        'description' => 'Updated',
    ]);

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

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

    $cashAccount = CashAccount::factory()->create(['balance' => 100000]);
    $cashTransaction = CashTransaction::factory()->create([
        'cash_account_id' => $cashAccount->id,
        'created_by_id' => $user->id,
        'type' => 'expense',
        'amount' => 30000,
        'balance_after' => 70000,
    ]);
    $expense = Expense::factory()->create([
        'cash_transaction_id' => $cashTransaction->id,
        'created_by_id' => $user->id,
        'amount' => 30000,
    ]);

    $response = $this->delete(route('admin.finance.expenses.destroy', $expense));

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

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

test('expense 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.expenses.store'), [
        'amount' => 50000,
        'description' => 'Test',
        'receipt_key' => str_repeat('a', 501),
    ]);

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

test('expense 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.expenses.store'), [
        'amount' => 50000,
        'description' => 'Test',
        'receipt_key' => str_repeat('a', 500),
    ]);

    $response->assertSessionHasNoErrors();
});
