<?php

namespace Tests\Feature;

use App\Domains\Event\Actions\CreateEvent\CreateEventCommand;
use App\Domains\Event\Actions\CreateEvent\CreateEventRequest;
use App\Enumerations\EatingHabit;
use App\Enumerations\ParticipationFeeType;
use App\Models\Event;
use App\Models\Tenant;
use App\RelationModels\EventParticipationFee;
use App\Resources\EventResource;
use DateTime;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;

class EventVatPricingTest extends TestCase
{
    use RefreshDatabase;

    private Tenant $tenant;

    protected function setUp(): void
    {
        parent::setUp();

        $this->tenant = Tenant::create([
            'slug' => 'tv',
            'name' => 'Test',
            'email' => 't@example.com',
            'email_finance' => 'finance@example.com',
            'url' => 'test.local',
            'account_name' => 'Test e.V.',
            'account_iban' => 'DE00',
            'account_bic' => 'XY',
            'city' => 'Stadt',
            'postcode' => '00000',
            'is_active_local_group' => true,
            'has_active_instance' => true,
        ]);

        app()->instance('tenant', $this->tenant);

        DB::table('participation_types')->insert(['slug' => 'participant', 'name' => 'Teilnehmer']);
        DB::table('participation_fee_types')->insert(['slug' => 'fixed', 'name' => 'Fix']);
        EatingHabit::create(['slug' => EatingHabit::EATING_HABIT_VEGAN, 'name' => 'Vegan']);
        EatingHabit::create(['slug' => EatingHabit::EATING_HABIT_VEGETARIAN, 'name' => 'Vegetarisch']);
    }

    private function makeFee(float $amountStandard): EventParticipationFee
    {
        return EventParticipationFee::create([
            'tenant' => $this->tenant->slug,
            'type' => 'participant',
            'name' => 'Standard',
            'description' => null,
            'amount_standard' => $amountStandard,
            'amount_reduced' => null,
            'amount_solidarity' => null,
        ]);
    }

    private function makeEvent(bool $taxLiable, int $vatRate, string $mode, int $feeId): Event
    {
        return Event::create([
            'tenant' => $this->tenant->slug,
            'name' => 'Event',
            'identifier' => 'evt-' . uniqid(),
            'location' => 'Ort',
            'postal_code' => '00000',
            'email' => 'e@example.com',
            'start_date' => '2026-09-01',
            'end_date' => '2026-09-05',
            'early_bird_end' => '2026-08-20',
            'registration_final_end' => '2026-08-25',
            'early_bird_end_amount_increase' => 0,
            'account_owner' => 'Owner',
            'account_iban' => 'DE00',
            'participation_fee_type' => 'fixed',
            'participation_fee_1' => $feeId,
            'pay_per_day' => false,
            'pay_direct' => false,
            'tax_liable' => $taxLiable,
            'vat_rate' => $vatRate,
            'vat_pricing_mode' => $mode,
        ]);
    }

    private function calculate(Event $event): float
    {
        return new EventResource($event)->calculateAmount(
            'participant',
            'standard',
            new DateTime('2026-09-01'),
            new DateTime('2026-09-01'),
            false,
        )->getAmount();
    }

    public function test_add_on_mode_adds_vat_on_top(): void
    {
        $event = $this->makeEvent(taxLiable: true, vatRate: 19, mode: 'add_on', feeId: $this->makeFee(100.0)->id);

        $this->assertEqualsWithDelta(119.0, $this->calculate($event), 0.001);
    }

    public function test_inclusive_mode_keeps_amount(): void
    {
        $event = $this->makeEvent(taxLiable: true, vatRate: 19, mode: 'inclusive', feeId: $this->makeFee(100.0)->id);

        $this->assertEqualsWithDelta(100.0, $this->calculate($event), 0.001);
    }

    public function test_not_liable_ignores_add_on_mode(): void
    {
        $event = $this->makeEvent(taxLiable: false, vatRate: 19, mode: 'add_on', feeId: $this->makeFee(100.0)->id);

        $this->assertEqualsWithDelta(100.0, $this->calculate($event), 0.001);
    }

    public function test_create_event_snapshots_tenant_tax_config(): void
    {
        $this->tenant->update([
            'tax_liable' => true,
            'vat_rate' => 7,
            'vat_pricing_mode' => 'add_on',
            'tax_exemption_reason' => null,
            'tax_exemption_note' => null,
        ]);

        $response = new CreateEventCommand(new CreateEventRequest(
            name: 'Sommerlager',
            location: 'Ort',
            postalCode: '00000',
            email: 'e@example.com',
            begin: new DateTime('2026-09-01'),
            end: new DateTime('2026-09-05'),
            earlyBirdEnd: new DateTime('2026-08-20'),
            registrationFinalEnd: new DateTime('2026-08-25'),
            earlyBirdEndAmountIncrease: 0,
            participationFeeType: ParticipationFeeType::where('slug', 'fixed')->first(),
            accountOwner: 'Owner',
            accountIban: 'DE00',
            payPerDay: false,
        ))->execute();

        $this->assertTrue($response->success);

        $event = $response->event->fresh();
        $this->assertTrue($event->tax_liable);
        $this->assertSame(7, $event->vat_rate);
        $this->assertSame('add_on', $event->vat_pricing_mode);
    }
}
