<?php

namespace Tests\Unit\Models;

use App\Enums\Status;
use App\Models\ExpenseRequest;
use App\Models\ExpenseType;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Testing\RefreshDatabase;
use OwenIt\Auditing\Auditable;
use Tests\TestCase;

class ExpenseTypeTest extends TestCase
{
    use RefreshDatabase;

    public function test_expense_type_has_correct_fillable_attributes(): void
    {
        $expenseType = new ExpenseType;
        $expectedFillable = [
            'name',
            'code',
            'notes',
            'default_amount',
            'max_amount',
            'is_proof_required',
            'status',
            'created_by_id',
            'updated_by_id',
        ];

        $this->assertEquals($expectedFillable, $expenseType->getFillable());
    }

    public function test_expense_type_has_correct_casts(): void
    {
        $expenseType = new ExpenseType;
        $casts = $expenseType->getCasts();

        $this->assertArrayHasKey('status', $casts);
        $this->assertArrayHasKey('default_amount', $casts);
        $this->assertArrayHasKey('max_amount', $casts);
        $this->assertArrayHasKey('is_proof_required', $casts);

        $this->assertEquals('float', $casts['default_amount']);
        $this->assertEquals('float', $casts['max_amount']);
        $this->assertEquals('boolean', $casts['is_proof_required']);
    }

    public function test_expense_type_casts_status_to_enum(): void
    {
        $expenseType = ExpenseType::factory()->create(['status' => Status::ACTIVE]);

        $this->assertInstanceOf(Status::class, $expenseType->status);
        $this->assertEquals(Status::ACTIVE, $expenseType->status);
    }

    public function test_expense_type_uses_soft_deletes(): void
    {
        $expenseType = new ExpenseType;
        $traits = class_uses_recursive($expenseType);

        $this->assertContains(SoftDeletes::class, $traits);
    }

    public function test_expense_type_uses_auditable_trait(): void
    {
        $expenseType = new ExpenseType;
        $traits = class_uses_recursive($expenseType);

        $this->assertContains(Auditable::class, $traits);
    }

    public function test_expense_type_has_expense_requests_relationship(): void
    {
        $expenseType = ExpenseType::factory()->create();
        $expenseRequest = ExpenseRequest::factory()->forExpenseType($expenseType)->create();

        $this->assertInstanceOf(\Illuminate\Database\Eloquent\Relations\HasMany::class, $expenseType->expenseRequests());
        $this->assertTrue($expenseType->expenseRequests->contains($expenseRequest));
    }

    public function test_active_scope_returns_only_active_types(): void
    {
        // Create active expense types
        ExpenseType::factory()->count(3)->active()->create();

        // Create inactive expense types
        ExpenseType::factory()->count(2)->inactive()->create();

        $activeTypes = ExpenseType::active()->get();

        $this->assertCount(3, $activeTypes);
        $activeTypes->each(function ($type) {
            $this->assertEquals(Status::ACTIVE, $type->status);
        });
    }

    public function test_expense_type_can_be_created_with_factory(): void
    {
        $expenseType = ExpenseType::factory()->create();

        $this->assertDatabaseHas('expense_types', [
            'id' => $expenseType->id,
            'name' => $expenseType->name,
        ]);
    }

    public function test_expense_type_factory_inactive_state(): void
    {
        $expenseType = ExpenseType::factory()->inactive()->create();

        $this->assertEquals(Status::INACTIVE, $expenseType->status);
    }

    public function test_expense_type_factory_proof_required_state(): void
    {
        $expenseType = ExpenseType::factory()->proofRequired()->create();

        $this->assertTrue($expenseType->is_proof_required);
    }

    public function test_expense_type_can_be_soft_deleted(): void
    {
        $expenseType = ExpenseType::factory()->create();
        $expenseType->delete();

        $this->assertSoftDeleted('expense_types', [
            'id' => $expenseType->id,
        ]);
    }
}
