<?php

namespace Tests\Feature;

use App\Domains\Event\Actions\SignUp\SignUpCommand;
use App\Domains\Event\Actions\SignUp\SignUpRequest;
use App\Enumerations\EatingHabit;
use App\Enumerations\EfzStatus;
use App\Enumerations\FirstAidPermission;
use App\Enumerations\ParticipationType;
use App\Enumerations\SwimmingPermission;
use App\Models\AvailablePaymentMethod;
use App\Models\Event;
use App\Models\PaymentMethod;
use App\Models\Tenant;
use App\Resources\AvailablePaymentMethodResource;
use App\ValueObjects\Amount;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;

class SignUpPaymentOptionsTest 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' => 'f@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);

        PaymentMethod::create(['slug' => PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION]);
        DB::table('participation_fee_types')->insert(['slug' => 'FIXED', 'name' => 'Fixed', 'created_at' => now(), 'updated_at' => now()]);
        ParticipationType::create(['slug' => ParticipationType::PARTICIPATION_TYPE_PARTICIPANT, 'name' => 'Teilnehmende']);
        EfzStatus::create(['slug' => EfzStatus::EFZ_STATUS_NOT_CHECKED, 'name' => 'Nicht geprüft']);
        EfzStatus::create(['slug' => EfzStatus::EFZ_STATUS_NOT_REQUIRED, 'name' => 'Nicht erforderlich']);
        SwimmingPermission::create(['slug' => SwimmingPermission::SWIMMING_PERMISSION_ALLOWED, 'name' => 'Darf baden', 'short' => 'Erteilt']);
        FirstAidPermission::create(['slug' => FirstAidPermission::FIRST_AID_PERMISSION_ALLOWED, 'name' => 'Zugestimmt', 'description' => '']);
        EatingHabit::create(['slug' => EatingHabit::EATING_HABIT_VEGAN, 'name' => 'Vegan']);
    }

    private function createEvent(): Event
    {
        return Event::create([
            'tenant' => $this->tenant->slug, 'name' => 'Event', 'identifier' => 'evt-1', 'location' => 'Ort',
            'postal_code' => '00000', 'email' => 'e@example.com', 'start_date' => '2026-08-01', 'end_date' => '2026-08-05',
            'early_bird_end' => '2026-07-01', 'registration_final_end' => '2026-07-20', 'early_bird_end_amount_increase' => 0,
            'account_owner' => 'Owner', 'account_iban' => 'DE00', 'participation_fee_type' => 'FIXED',
            'pay_per_day' => false, 'pay_direct' => false,
        ]);
    }

    private function signUpRequest(Event $event, array $paymentOptions): SignUpRequest
    {
        return new SignUpRequest(
            $event, null, 'Hans', 'Muster', null, ParticipationType::PARTICIPATION_TYPE_PARTICIPANT,
            $this->tenant, new \DateTime('2000-01-01'), 'Weg 1', null, '00000', 'Stadt',
            'h@example.com', '123', null, null, null, null, null, null, null,
            'vegan', null, null, false, false, false, false, false,
            new \DateTime('2026-08-01'), new \DateTime('2026-08-05'), 0, 0, null,
            new Amount(50.0, ' Euro'), PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION, $paymentOptions,
        );
    }

    public function test_payment_options_are_sanitized_and_stored(): void
    {
        $event = $this->createEvent();

        // Überweisung hat keine Teilnehmer-Eingaben -> alles wird verworfen, payment_options bleibt leer.
        $response = new SignUpCommand($this->signUpRequest($event, ['evil' => 'x']))->execute();

        $this->assertTrue($response->success);
        $this->assertSame([], $response->participant->payment_options);
        // payment_purpose wird immer erzeugt (AC #4).
        $this->assertStringContainsString('Beitrag Hans Muster', $response->participant->payment_purpose);
    }

    public function test_resource_exposes_participant_options_schema(): void
    {
        $event = $this->createEvent();
        AvailablePaymentMethod::create([
            'tenant' => $this->tenant->slug, 'slug' => PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION,
            'name' => 'Überweisung', 'active' => true, 'configuration' => ['account_owner' => 'Kasse', 'iban' => 'DE1'],
        ]);

        $method = AvailablePaymentMethod::where('slug', PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION)->first();
        $array = new AvailablePaymentMethodResource($method)->toArray(request());

        $this->assertArrayHasKey('participantOptionsSchema', $array);
        $this->assertSame([], $array['participantOptionsSchema']); // Überweisung: keine Teilnehmer-Eingaben
    }

    public function test_payment_methods_serialize_without_data_wrapper(): void
    {
        AvailablePaymentMethod::create([
            'tenant' => $this->tenant->slug, 'slug' => PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION,
            'name' => 'Überweisung', 'active' => true, 'configuration' => ['account_owner' => 'Kasse', 'iban' => 'DE1'],
        ]);
        $method = AvailablePaymentMethod::where('slug', PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION)->first();

        // Exakt so serialisiert EventResource die Methoden fürs Frontend.
        $serialized = collect([$method])->map(
            fn($m) => new AvailablePaymentMethodResource($m)->toArray(request())
        )->toArray();

        // Kein data-Wrapper: slug/active liegen top-level (sonst wäre m.active im Frontend undefined -> leere Liste).
        $this->assertArrayNotHasKey('data', $serialized[0]);
        $this->assertSame(PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION, $serialized[0]['slug']);
        $this->assertTrue($serialized[0]['active']);
    }
}
