<?php

namespace Tests\Unit\AccountingCore\Models;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Modules\AccountingCore\App\Models\TaxRate;
use Tests\TestCase;
use Tests\Traits\CreatesAccountingCoreEntities;
use Tests\Traits\CreatesUsers;

class TaxRateTest extends TestCase
{
    use CreatesAccountingCoreEntities;
    use CreatesUsers;
    use RefreshDatabase;

    // ==========================================
    // Creation Tests
    // ==========================================

    public function test_can_create_tax_rate_with_required_fields(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = TaxRate::create([
            'name' => 'Standard VAT',
            'rate' => 15.00,
            'type' => 'percentage',
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $this->assertNotNull($taxRate->id);
        $this->assertEquals('Standard VAT', $taxRate->name);
        $this->assertEquals(15.00, $taxRate->rate);
        $this->assertEquals('percentage', $taxRate->type);
        $this->assertTrue($taxRate->is_active);
    }

    public function test_can_create_percentage_tax_rate(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createPercentageTaxRate(10.00, ['created_by_id' => $admin->id]);

        $this->assertEquals('percentage', $taxRate->type);
        $this->assertEquals(10.00, $taxRate->rate);
    }

    public function test_can_create_fixed_tax_rate(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createFixedTaxRate(50.00, ['created_by_id' => $admin->id]);

        $this->assertEquals('fixed', $taxRate->type);
        $this->assertEquals(50.00, $taxRate->rate);
    }

    // ==========================================
    // Casting Tests
    // ==========================================

    public function test_rate_casts_to_decimal(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createTaxRate([
            'rate' => 15.5555,
            'created_by_id' => $admin->id,
        ]);

        $this->assertIsNumeric($taxRate->rate);
        // decimal:4 preserves 4 decimal places
        $this->assertEquals(15.5555, $taxRate->rate);
    }

    public function test_is_default_casts_to_boolean(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createTaxRate([
            'is_default' => 1,
            'created_by_id' => $admin->id,
        ]);

        $this->assertIsBool($taxRate->is_default);
        $this->assertTrue($taxRate->is_default);
    }

    public function test_is_active_casts_to_boolean(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createTaxRate([
            'is_active' => 0,
            'created_by_id' => $admin->id,
        ]);

        $this->assertIsBool($taxRate->is_active);
        $this->assertFalse($taxRate->is_active);
    }

    // ==========================================
    // Scope Tests
    // ==========================================

    public function test_active_scope_filters_correctly(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $activeTaxRate = $this->createTaxRate([
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);
        $inactiveTaxRate = $this->createTaxRate([
            'is_active' => false,
            'created_by_id' => $admin->id,
        ]);

        $activeRates = TaxRate::active()->get();

        $this->assertTrue($activeRates->contains($activeTaxRate));
        $this->assertFalse($activeRates->contains($inactiveTaxRate));
    }

    // ==========================================
    // Static Method Tests
    // ==========================================

    public function test_get_default_returns_active_default_tax_rate(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $defaultRate = $this->createDefaultTaxRate(['created_by_id' => $admin->id]);
        $otherRate = $this->createTaxRate(['created_by_id' => $admin->id]);

        $result = TaxRate::getDefault();

        $this->assertNotNull($result);
        $this->assertEquals($defaultRate->id, $result->id);
    }

    public function test_get_default_returns_null_when_no_default(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $this->createTaxRate([
            'is_default' => false,
            'created_by_id' => $admin->id,
        ]);

        $result = TaxRate::getDefault();

        $this->assertNull($result);
    }

    public function test_get_default_returns_null_when_default_is_inactive(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        TaxRate::create([
            'name' => 'Inactive Default',
            'rate' => 10.00,
            'type' => 'percentage',
            'is_default' => true,
            'is_active' => false,
            'created_by_id' => $admin->id,
        ]);

        $result = TaxRate::getDefault();

        $this->assertNull($result);
    }

    public function test_get_active_returns_ordered_by_name(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $this->createTaxRate(['name' => 'Zebra Tax', 'is_active' => true, 'created_by_id' => $admin->id]);
        $this->createTaxRate(['name' => 'Alpha Tax', 'is_active' => true, 'created_by_id' => $admin->id]);
        $this->createTaxRate(['name' => 'Beta Tax', 'is_active' => true, 'created_by_id' => $admin->id]);
        $this->createTaxRate(['name' => 'Inactive Tax', 'is_active' => false, 'created_by_id' => $admin->id]);

        $active = TaxRate::getActive();

        $this->assertCount(3, $active);
        $this->assertEquals('Alpha Tax', $active->first()->name);
        $this->assertEquals('Zebra Tax', $active->last()->name);
    }

    // ==========================================
    // Instance Method Tests
    // ==========================================

    public function test_set_as_default_unsets_other_defaults(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $rate1 = $this->createDefaultTaxRate(['name' => 'Rate 1', 'created_by_id' => $admin->id]);
        $rate2 = $this->createTaxRate(['name' => 'Rate 2', 'is_default' => false, 'created_by_id' => $admin->id]);

        $rate2->setAsDefault();

        $rate1->refresh();
        $rate2->refresh();

        $this->assertFalse($rate1->is_default);
        $this->assertTrue($rate2->is_default);
    }

    public function test_is_in_use_returns_false_currently(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createTaxRate(['created_by_id' => $admin->id]);

        // Currently isInUse() always returns false as noted in the code
        $this->assertFalse($taxRate->isInUse());
    }

    // ==========================================
    // Tax Calculation Tests
    // ==========================================

    public function test_calculate_tax_with_percentage_type(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createPercentageTaxRate(10.00, ['created_by_id' => $admin->id]);

        $tax = $taxRate->calculateTax(1000);

        $this->assertEquals(100, $tax); // 10% of 1000 = 100
    }

    public function test_calculate_tax_with_fixed_type(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createFixedTaxRate(50.00, ['created_by_id' => $admin->id]);

        $tax = $taxRate->calculateTax(1000);

        $this->assertEquals(50, $tax); // Fixed amount regardless of base
    }

    public function test_calculate_tax_with_zero_rate(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createPercentageTaxRate(0, ['created_by_id' => $admin->id]);

        $tax = $taxRate->calculateTax(1000);

        $this->assertEquals(0, $tax);
    }

    public function test_calculate_tax_with_large_amount(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createPercentageTaxRate(15.00, ['created_by_id' => $admin->id]);

        $tax = $taxRate->calculateTax(1000000);

        $this->assertEquals(150000, $tax); // 15% of 1,000,000
    }

    public function test_calculate_tax_with_decimal_precision(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createPercentageTaxRate(7.5, ['created_by_id' => $admin->id]);

        $tax = $taxRate->calculateTax(199.99);

        // Use delta comparison for floating-point precision
        $this->assertEqualsWithDelta(14.99925, $tax, 0.00001); // 7.5% of 199.99
    }

    public function test_calculate_tax_with_zero_amount(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createPercentageTaxRate(10.00, ['created_by_id' => $admin->id]);

        $tax = $taxRate->calculateTax(0);

        $this->assertEquals(0, $tax);
    }

    // ==========================================
    // Accessor Tests
    // ==========================================

    public function test_formatted_rate_shows_percentage_symbol(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createPercentageTaxRate(15.00, ['created_by_id' => $admin->id]);

        $this->assertEquals('15.00%', $taxRate->formatted_rate);
    }

    public function test_formatted_rate_without_percentage_for_fixed(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createFixedTaxRate(50.00, ['created_by_id' => $admin->id]);

        $this->assertEquals('50.00', $taxRate->formatted_rate);
    }

    // ==========================================
    // Soft Delete Tests
    // ==========================================

    public function test_tax_rate_can_be_soft_deleted(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createTaxRate(['created_by_id' => $admin->id]);
        $taxRateId = $taxRate->id;

        $taxRate->delete();

        $this->assertSoftDeleted('tax_rates', ['id' => $taxRateId]);
    }

    public function test_tax_rate_can_be_restored(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $taxRate = $this->createTaxRate(['created_by_id' => $admin->id]);
        $taxRate->delete();
        $taxRate->restore();

        $this->assertDatabaseHas('tax_rates', [
            'id' => $taxRate->id,
            'deleted_at' => null,
        ]);
    }
}
