<?php

namespace App\Domains\Event\Actions\SignUp;

use App\Enumerations\EatingHabit;
use App\Enumerations\EfzStatus;
use App\EventPaymentModules\EventPaymentModuleRegistry;
use App\ValueObjects\Age;
use Illuminate\Support\Str;

class SignUpCommand {
    public function __construct(public SignUpRequest $request) {
    }

    public function execute() : SignUpResponse {
        $response = new SignUpResponse();

        // Teilnehmer-Eingaben der gewählten Zahlungsart gegen das Modul-Schema absichern.
        $module = $this->request->paymentMethod !== null
            ? EventPaymentModuleRegistry::forSlug($this->request->paymentMethod)
            : null;
        $paymentOptions = $module?->sanitizeParticipantOptions($this->request->paymentOptions) ?? [];

        if ($module !== null && !$module->participantOptionsComplete($paymentOptions)) {
            $response->success = false;
            $response->message = 'Bitte alle erforderlichen Zahlungsangaben ausfüllen.';
            return $response;
        }

        // Teilnahmeoptionen (event-spezifische Pflicht-Auswahl) gegen die Event-Definition absichern.
        $participationOptionRows = $this->buildParticipationOptionRows();
        if ($participationOptionRows === null) {
            $response->success = false;
            $response->message = 'Bitte alle Auswahlfelder ausfüllen.';
            return $response;
        }

        $eatingHabit = match ($this->request->eating_habit) {
            'vegan' => EatingHabit::EATING_HABIT_VEGAN,
            'vegetarian' => EatingHabit::EATING_HABIT_VEGETARIAN,
            default => EatingHabit::EATING_HABIT_OMNIVOR,
        };

        $participantAge = new Age($this->request->birthday);

        $response->participant = $this->request->event->participants()->create(
            [
                'tenant' => $this->request->event->tenant,
                'user_id' => $this->request->user_id,
                'identifier' => Str::random(10),
                'firstname' => $this->request->firstname,
                'lastname' => $this->request->lastname,
                'nickname' => $this->request->nickname,
                'participation_type' => $this->request->participationType,
                'local_group' => $this->request->localGroup->slug,
                'birthday' => $this->request->birthday,
                'address_1' => $this->request->address_1,
                'address_2' => $this->request->address_2,
                'postcode' => $this->request->postcode,
                'city' => $this->request->city,
                'email_1' => $this->request->email_1,
                'email_2' => $this->request->email_2,
                'phone_1' => $this->request->phone_1,
                'phone_2' => $this->request->phone_2,
                'contact_person' => $this->request->contact_person,
                'allergies' => $this->request->allergies,
                'intolerances' => $this->request->intolerances,
                'medications' => $this->request->medications,
                'tetanus_vaccination' => $this->request->tetanus_vaccination,
                'eating_habit' => $eatingHabit,
                'swimming_permission' => $participantAge->isfullAged() ? 'SWIMMING_PERMISSION_ALLOWED' : $this->request->swimming_permission,
                'first_aid_permission' => $participantAge->isfullAged() ? 'FIRST_AID_PERMISSION_ALLOWED' : $this->request->first_aid_permission,
                'foto_socialmedia' => $this->request->foto_socialmedia,
                'foto_print' => $this->request->foto_print,
                'foto_webseite' => $this->request->foto_webseite,
                'foto_partner' => $this->request->foto_partner,
                'foto_intern' => $this->request->foto_intern,
                'arrival_date' => $this->request->arrival,
                'departure_date' => $this->request->departure,
                'arrival_eating' => $this->request->arrival_eating,
                'departure_eating' => $this->request->departure_eating,
                'notes' => $this->request->notes,
                'amount' => $this->request->amount,
                'payment_purpose' => $this->request->event->name . ' - Beitrag ' . $this->request->firstname . ' ' . $this->request->lastname,
                'payment_method' => $this->request->paymentMethod,
                'payment_options' => $paymentOptions,
                'efz_status' => $participantAge->isfullAged() ? EfzStatus::EFZ_STATUS_NOT_CHECKED : EfzStatus::EFZ_STATUS_NOT_REQUIRED,
            ]
        );

        $this->persistParticipationOptions($response->participant, $participationOptionRows);
        $this->persistAddons($response->participant);

        $response->success = true;
        return $response;
    }

    /**
     * Speichert die gewählten Zusätze (Event-Addons) als Snapshot-Zeilen (Titel/Preis/Betrag) für die spätere
     * Rechnung. Die Beträge sind bereits in der Controller-Auflösung (`resolveAddons`) berechnet, inkl. USt.
     */
    private function persistAddons(\App\Models\EventParticipant $participant): void
    {
        foreach ($this->request->addonItems as $item) {
            $participant->selectedAddons()->create([
                'tenant' => $this->request->event->tenant,
                'event_id' => $this->request->event->id,
                'addon_key' => $item['key'],
                'title' => $item['title'],
                'price' => $item['price'] ?? 0,
                'flat' => (bool)($item['flat'] ?? false),
                'days' => $item['days'] ?? 0,
                'amount' => $item['amount'] ?? 0,
            ]);
        }
    }

    /**
     * Validiert die Antworten gegen die am Event definierten Teilnahmeoptionen und erzeugt die zu speichernden
     * Zeilen mit Label-Snapshots. Gibt null zurück, wenn eine Pflicht-Frage unbeantwortet oder eine Antwort
     * ungültig ist (Absicherung gegen manipulierte Payloads).
     *
     * @return array<int, array{question_key: string, question_label: string, value: string, value_label: string}>|null
     */
    private function buildParticipationOptionRows(): ?array
    {
        $rows = [];

        foreach ($this->request->event->participation_options ?? [] as $question) {
            $key = $question['key'] ?? null;
            if ($key === null) {
                continue;
            }

            $value = $this->request->participationOptions[$key] ?? null;
            if ($value === null || $value === '') {
                return null;
            }

            $option = null;
            foreach ($question['options'] ?? [] as $candidate) {
                if (($candidate['value'] ?? null) === $value) {
                    $option = $candidate;
                    break;
                }
            }

            if ($option === null) {
                return null;
            }

            $rows[] = [
                'question_key' => $key,
                'question_label' => $question['label'] ?? $key,
                'value' => $value,
                'value_label' => $option['label'] ?? $value,
            ];
        }

        return $rows;
    }

    /**
     * @param array<int, array{question_key: string, question_label: string, value: string, value_label: string}> $rows
     */
    private function persistParticipationOptions(\App\Models\EventParticipant $participant, array $rows): void
    {
        foreach ($rows as $row) {
            $participant->selectedOptions()->create(array_merge($row, [
                'tenant' => $this->request->event->tenant,
                'event_id' => $this->request->event->id,
            ]));
        }
    }

}
