<?php

namespace Tests\Unit\SystemCore;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Modules\SystemCore\App\Models\CoreTaxConfiguration;
use Tests\TestCase;
use Tests\Traits\CreatesSystemCoreEntities;
use Tests\Traits\CreatesUsers;

class TaxCalculationTest extends TestCase
{
    use CreatesSystemCoreEntities;
    use CreatesUsers;
    use RefreshDatabase;

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

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

        $tax = $this->createCoreTaxConfiguration([
            'rate' => 5.0,
            'type' => 'percentage',
            'created_by_id' => $admin->id,
        ]);

        $taxAmount = $tax->calculateTax(100.00);

        $this->assertEquals(5.00, $taxAmount);
    }

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

        $tax = $this->createCoreTaxConfiguration([
            'rate' => 18.0, // GST-like rate
            'type' => 'percentage',
            'created_by_id' => $admin->id,
        ]);

        $taxAmount = $tax->calculateTax(1500.00);

        $this->assertEquals(270.00, $taxAmount);
    }

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

        $tax = $this->createCoreTaxConfiguration([
            'rate' => 10.00,
            'type' => 'fixed',
            'created_by_id' => $admin->id,
        ]);

        // Fixed tax should return the rate regardless of amount
        $this->assertEquals(10.00, $tax->calculateTax(100.00));
        $this->assertEquals(10.00, $tax->calculateTax(1000.00));
        $this->assertEquals(10.00, $tax->calculateTax(50.00));
    }

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

        $tax = $this->createCoreTaxConfiguration([
            'rate' => 0,
            'type' => 'percentage',
            'created_by_id' => $admin->id,
        ]);

        $taxAmount = $tax->calculateTax(1000.00);

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

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

        $tax = $this->createCoreTaxConfiguration([
            'rate' => 5.5,
            'type' => 'percentage',
            'created_by_id' => $admin->id,
        ]);

        $taxAmount = $tax->calculateTax(1000000.00);

        $this->assertEquals(55000.00, $taxAmount);
    }

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

        $tax = $this->createCoreTaxConfiguration([
            'rate' => 5.25,
            'type' => 'percentage',
            'created_by_id' => $admin->id,
        ]);

        $taxAmount = $tax->calculateTax(99.99);

        $this->assertEqualsWithDelta(5.2495, $taxAmount, 0.01);
    }

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

        $tax = $this->createCoreTaxConfiguration([
            'rate' => 5.0,
            'type' => 'percentage',
            'created_by_id' => $admin->id,
        ]);

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

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

    // ==========================================
    // Formatted Rate Tests
    // ==========================================

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

        $tax = $this->createCoreTaxConfiguration([
            'rate' => 5.0,
            'type' => 'percentage',
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('5.00%', $tax->formatted_rate);
    }

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

        $tax = $this->createCoreTaxConfiguration([
            'rate' => 10.50,
            'type' => 'fixed',
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('10.50', $tax->formatted_rate);
    }

    // ==========================================
    // Default Tax Tests
    // ==========================================

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

        // Create non-default taxes
        $this->createCoreTaxConfiguration([
            'is_default' => false,
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        // Create default tax
        $defaultTax = $this->createDefaultTaxConfiguration(['created_by_id' => $admin->id]);

        $result = CoreTaxConfiguration::getDefault();

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

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

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

        $result = CoreTaxConfiguration::getDefault();

        $this->assertNull($result);
    }

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

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

        $result = CoreTaxConfiguration::getDefault();

        $this->assertNull($result);
    }

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

        $oldDefault = $this->createDefaultTaxConfiguration([
            'name' => 'Old Default',
            'created_by_id' => $admin->id,
        ]);

        $newTax = $this->createCoreTaxConfiguration([
            'name' => 'New Tax',
            'is_default' => false,
            'created_by_id' => $admin->id,
        ]);

        // Set new tax as default
        $newTax->setAsDefault();

        // Refresh from database
        $oldDefault->refresh();
        $newTax->refresh();

        $this->assertFalse($oldDefault->is_default);
        $this->assertTrue($newTax->is_default);
    }

    // ==========================================
    // In Use Tests
    // ==========================================

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

        $tax = $this->createCoreTaxConfiguration(['created_by_id' => $admin->id]);

        // Create a product with this tax
        $this->createCoreProduct([
            'tax_id' => $tax->id,
            'created_by_id' => $admin->id,
        ]);

        $this->assertTrue($tax->isInUse());
    }

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

        $tax = $this->createCoreTaxConfiguration(['created_by_id' => $admin->id]);

        $this->assertFalse($tax->isInUse());
    }

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

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

        $activeTax = $this->createCoreTaxConfiguration([
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $inactiveTax = $this->createCoreTaxConfiguration([
            'is_active' => false,
            'created_by_id' => $admin->id,
        ]);

        $activeTaxes = CoreTaxConfiguration::active()->get();

        $this->assertTrue($activeTaxes->contains($activeTax));
        $this->assertFalse($activeTaxes->contains($inactiveTax));
    }

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

        $taxC = $this->createCoreTaxConfiguration([
            'name' => 'C Tax',
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $taxA = $this->createCoreTaxConfiguration([
            'name' => 'A Tax',
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $taxB = $this->createCoreTaxConfiguration([
            'name' => 'B Tax',
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $activeTaxes = CoreTaxConfiguration::getActive();

        $this->assertEquals('A Tax', $activeTaxes->first()->name);
        $this->assertEquals('C Tax', $activeTaxes->last()->name);
    }

    // ==========================================
    // Products Relationship Test
    // ==========================================

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

        $tax = $this->createCoreTaxConfiguration(['created_by_id' => $admin->id]);

        $product1 = $this->createCoreProduct([
            'tax_id' => $tax->id,
            'created_by_id' => $admin->id,
        ]);

        $product2 = $this->createCoreProduct([
            'tax_id' => $tax->id,
            'created_by_id' => $admin->id,
        ]);

        // Product without this tax
        $this->createCoreProduct([
            'tax_id' => null,
            'created_by_id' => $admin->id,
        ]);

        $taxProducts = $tax->products;

        $this->assertCount(2, $taxProducts);
        $this->assertTrue($taxProducts->contains($product1));
        $this->assertTrue($taxProducts->contains($product2));
    }
}
