<?php

namespace Tests\Feature;

use App\Enums\JournalSource;
use App\Enums\JournalStatus;
use App\Models\Account;
use App\Models\User;
use App\Services\Accounting\JournalService;
use App\Services\Accounting\OpeningBalanceService;
use Database\Seeders\ChartOfAccountsSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AccountingCoreTest extends TestCase
{
    use RefreshDatabase;

    public function test_opening_balance_posts_balanced_journal_to_opening_balance_equity(): void
    {
        $this->seed(ChartOfAccountsSeeder::class);

        $account = Account::query()->create([
            'code' => '9999',
            'name' => 'Test Cash',
            'category' => 'asset',
            'account_type' => 'current_asset',
            'normal_balance_side' => 'debit',
            'opening_balance' => 1500.00,
            'opening_balance_date' => now()->toDateString(),
            'status' => 'active',
        ]);

        $entry = app(OpeningBalanceService::class)->postForAccount($account);

        $this->assertNotNull($entry);
        $this->assertSame(JournalSource::OpeningBalance, $entry->source);
        $this->assertSame(JournalStatus::Posted, $entry->status);
        $this->assertCount(2, $entry->lines);

        $obe = Account::query()->where('code', '3099')->firstOrFail();
        $this->assertSame('1500.00', number_format((float) $entry->lines->firstWhere('account_id', $account->id)->debit_amount, 2, '.', ''));
        $this->assertSame('1500.00', number_format((float) $entry->lines->firstWhere('account_id', $obe->id)->credit_amount, 2, '.', ''));
    }

    public function test_journal_void_only_works_for_entries_posted_today(): void
    {
        $this->seed(ChartOfAccountsSeeder::class);
        $user = User::factory()->create();

        $cash = Account::query()->where('code', '1001')->firstOrFail();
        $obe = Account::query()->where('code', '3099')->firstOrFail();

        $entry = app(JournalService::class)->post([
            'date' => now()->toDateString(),
            'description' => 'Test entry',
            'source' => JournalSource::ManualAdjustment->value,
            'posted_by' => $user->id,
        ], [
            ['account_id' => $cash->id, 'debit_amount' => 100, 'credit_amount' => 0],
            ['account_id' => $obe->id, 'debit_amount' => 0, 'credit_amount' => 100],
        ]);

        $voided = app(JournalService::class)->void($entry, 'Entered in error');

        $this->assertSame(JournalStatus::Voided, $voided->status);
        $this->assertSame('Entered in error', $voided->void_reason);
    }
}
