<?php

declare(strict_types=1);

use App\Models\TaxRate;
use App\Models\User;
use Database\Seeders\RoleAndPermissionSeeder;

beforeEach(function (): void {
    $this->seed(RoleAndPermissionSeeder::class);
    $this->adminUrl = 'http://'.config('app.domains.admin');
});

// ---------------------------------------------------------------------------
// Index
// ---------------------------------------------------------------------------
describe('Tax Rate Index', function (): void {
    it('allows admin to list tax rates', function (): void {
        $admin = User::factory()->admin()->create();
        TaxRate::factory()->count(3)->create();

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tax-rates')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/TaxRates/Index')
                ->has('taxRates.data', 3)
                ->has('countries')
                ->has('filters')
            );
    });

    it('filters tax rates by country', function (): void {
        $admin = User::factory()->admin()->create();
        TaxRate::factory()->forCountry('US')->create();
        TaxRate::factory()->forCountry('DE')->create();
        TaxRate::factory()->forCountry('US', 'CA')->create();

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tax-rates?country=US')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/TaxRates/Index')
                ->has('taxRates.data', 2)
            );
    });

    it('filters tax rates by active status', function (): void {
        $admin = User::factory()->admin()->create();
        TaxRate::factory()->count(2)->create(['is_active' => true]);
        TaxRate::factory()->inactive()->create();

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tax-rates?status=active')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/TaxRates/Index')
                ->has('taxRates.data', 2)
            );
    });

    it('searches tax rates by name', function (): void {
        $admin = User::factory()->admin()->create();
        TaxRate::factory()->create(['name' => 'EU VAT Germany']);
        TaxRate::factory()->create(['name' => 'US Sales Tax']);

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tax-rates?search=VAT')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/TaxRates/Index')
                ->has('taxRates.data', 1)
            );
    });

    it('denies non-admin access to tax rates', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->get($this->adminUrl.'/tax-rates')
            ->assertForbidden();
    });
});

// ---------------------------------------------------------------------------
// Create
// ---------------------------------------------------------------------------
describe('Tax Rate Create', function (): void {
    it('displays the create tax rate page', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tax-rates/create')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/TaxRates/Create')
            );
    });

    it('stores a new tax rate', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tax-rates', [
                'name' => 'EU VAT - Germany',
                'country_code' => 'DE',
                'region_code' => null,
                'rate' => 19.00,
                'type' => 'inclusive',
                'priority' => 0,
                'is_active' => true,
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('tax_rates', [
            'name' => 'EU VAT - Germany',
            'country_code' => 'DE',
            'rate' => '19.00',
            'type' => 'inclusive',
            'is_active' => true,
        ]);
    });

    it('stores a tax rate with region code', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tax-rates', [
                'name' => 'US Sales Tax - California',
                'country_code' => 'US',
                'region_code' => 'CA',
                'rate' => 7.25,
                'type' => 'exclusive',
                'priority' => 1,
                'is_active' => true,
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('tax_rates', [
            'name' => 'US Sales Tax - California',
            'country_code' => 'US',
            'region_code' => 'CA',
            'rate' => '7.25',
            'type' => 'exclusive',
        ]);
    });

    it('uppercases country code on store', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tax-rates', [
                'name' => 'Test Tax',
                'country_code' => 'de',
                'rate' => 10.00,
                'type' => 'exclusive',
                'priority' => 0,
                'is_active' => true,
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('tax_rates', [
            'country_code' => 'DE',
        ]);
    });

    it('validates required fields when storing', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tax-rates', [])
            ->assertSessionHasErrors(['name', 'country_code', 'rate', 'type']);
    });

    it('validates rate range', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tax-rates', [
                'name' => 'Invalid Rate',
                'country_code' => 'US',
                'rate' => 150,
                'type' => 'exclusive',
            ])
            ->assertSessionHasErrors(['rate']);
    });

    it('validates country code format', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tax-rates', [
                'name' => 'Bad Country',
                'country_code' => 'USA',
                'rate' => 10,
                'type' => 'exclusive',
            ])
            ->assertSessionHasErrors(['country_code']);
    });

    it('validates type enum', function (): void {
        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tax-rates', [
                'name' => 'Bad Type',
                'country_code' => 'US',
                'rate' => 10,
                'type' => 'invalid',
            ])
            ->assertSessionHasErrors(['type']);
    });
});

// ---------------------------------------------------------------------------
// Edit / Update
// ---------------------------------------------------------------------------
describe('Tax Rate Edit', function (): void {
    it('displays the edit tax rate page', function (): void {
        $admin = User::factory()->admin()->create();
        $taxRate = TaxRate::factory()->create();

        $this->actingAs($admin)
            ->get($this->adminUrl.'/tax-rates/'.$taxRate->id.'/edit')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/TaxRates/Edit')
                ->has('taxRate')
            );
    });

    it('updates an existing tax rate', function (): void {
        $admin = User::factory()->admin()->create();
        $taxRate = TaxRate::factory()->create([
            'name' => 'Old Name',
            'rate' => '10.00',
        ]);

        $this->actingAs($admin)
            ->put($this->adminUrl.'/tax-rates/'.$taxRate->id, [
                'name' => 'New Name',
                'country_code' => $taxRate->country_code,
                'region_code' => $taxRate->region_code,
                'rate' => 15.00,
                'type' => $taxRate->type,
                'priority' => 0,
                'is_active' => true,
            ])
            ->assertRedirect();

        $fresh = $taxRate->fresh();
        expect($fresh->name)->toBe('New Name');
        expect((float) $fresh->rate)->toBe(15.0);
    });
});

// ---------------------------------------------------------------------------
// Delete
// ---------------------------------------------------------------------------
describe('Tax Rate Delete', function (): void {
    it('deletes a tax rate', function (): void {
        $admin = User::factory()->admin()->create();
        $taxRate = TaxRate::factory()->create();

        $this->actingAs($admin)
            ->delete($this->adminUrl.'/tax-rates/'.$taxRate->id)
            ->assertRedirect();

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

// ---------------------------------------------------------------------------
// Toggle Active
// ---------------------------------------------------------------------------
describe('Tax Rate Toggle Active', function (): void {
    it('toggles a tax rate from active to inactive', function (): void {
        $admin = User::factory()->admin()->create();
        $taxRate = TaxRate::factory()->create(['is_active' => true]);

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tax-rates/'.$taxRate->id.'/toggle-active')
            ->assertRedirect();

        expect($taxRate->fresh()->is_active)->toBeFalse();
    });

    it('toggles a tax rate from inactive to active', function (): void {
        $admin = User::factory()->admin()->create();
        $taxRate = TaxRate::factory()->inactive()->create();

        $this->actingAs($admin)
            ->post($this->adminUrl.'/tax-rates/'.$taxRate->id.'/toggle-active')
            ->assertRedirect();

        expect($taxRate->fresh()->is_active)->toBeTrue();
    });
});

// ---------------------------------------------------------------------------
// Model: getApplicableRates
// ---------------------------------------------------------------------------
describe('TaxRate::getApplicableRates', function (): void {
    it('returns matching rates for a country', function (): void {
        TaxRate::factory()->forCountry('US')->create(['rate' => '8.00', 'priority' => 0]);
        TaxRate::factory()->forCountry('DE')->create(['rate' => '19.00']);

        $rates = TaxRate::getApplicableRates('US');

        expect($rates)->toHaveCount(1);
        expect((float) $rates->first()->rate)->toBe(8.0);
    });

    it('returns country-level and region-level rates when region is specified', function (): void {
        TaxRate::factory()->forCountry('US')->create(['rate' => '5.00', 'priority' => 0]);
        TaxRate::factory()->forCountry('US', 'CA')->create(['rate' => '7.25', 'priority' => 1]);
        TaxRate::factory()->forCountry('US', 'NY')->create(['rate' => '8.00', 'priority' => 1]);

        $rates = TaxRate::getApplicableRates('US', 'CA');

        expect($rates)->toHaveCount(2);
        expect((float) $rates->first()->rate)->toBe(5.0);
        expect((float) $rates->last()->rate)->toBe(7.25);
    });

    it('excludes inactive rates', function (): void {
        TaxRate::factory()->forCountry('GB')->create(['is_active' => true]);
        TaxRate::factory()->forCountry('GB')->inactive()->create(['type' => 'inclusive']);

        $rates = TaxRate::getApplicableRates('GB');

        expect($rates)->toHaveCount(1);
    });

    it('orders rates by priority', function (): void {
        TaxRate::factory()->forCountry('FR')->create([
            'name' => 'Low Priority',
            'rate' => '5.00',
            'priority' => 2,
        ]);
        TaxRate::factory()->forCountry('FR')->create([
            'name' => 'High Priority',
            'rate' => '20.00',
            'priority' => 0,
            'type' => 'inclusive',
        ]);

        $rates = TaxRate::getApplicableRates('FR');

        expect($rates)->toHaveCount(2);
        expect($rates->first()->name)->toBe('High Priority');
        expect($rates->last()->name)->toBe('Low Priority');
    });

    it('returns empty collection when no rates match', function (): void {
        TaxRate::factory()->forCountry('US')->create();

        $rates = TaxRate::getApplicableRates('ZZ');

        expect($rates)->toBeEmpty();
    });
});
