<?php

namespace App\Domains\Event\Controllers;

use App\Domains\Event\Actions\CertificateOfConductionCheck\CertificateOfConductionCheckCommand;
use App\Domains\Event\Actions\CertificateOfConductionCheck\CertificateOfConductionCheckRequest;
use App\Domains\Event\Actions\SignUp\SignUpCommand;
use App\Domains\Event\Actions\SignUp\SignUpRequest;
use App\Mail\ParticipantParticipationMails\EventSignUpSuccessfullMail;
use App\Models\Tenant;
use App\Providers\DoubleCheckEventRegistrationProvider;
use App\Providers\InertiaProvider;
use App\Resources\UserResource;
use App\Scopes\CommonController;
use App\ValueObjects\Amount;
use DateTime;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;

class SignupController extends CommonController {
    public function __invoke(string $eventId, Request $request) {
        $availableEvents = [];
        foreach ($this->events->getAvailable(false) as $event) {
            $availableEvents[] = $event->toResource()->toArray($request);
        };

        $eventModel = $this->events->getByIdentifier($eventId, false);
        $event = $eventModel?->toResource()->toArray($request);
        // Die (aktiven) Zahlungsmethoden stehen dem Frontend über $event['paymentMethods'] zur Verfügung;
        // die Auswahl trifft der/die Teilnehmer\*in im Anmeldeschritt "Zahlungsart".

        $participantData = [
            'firstname' => '',
            'lastname' => '',
        ];

        if (auth()->check()) {
            $user = new UserResource(auth()->user())->toArray($request);

            $participantData = [
                'id' => $user['id'],
                'firstname' => $user['firstname'],
                'lastname' => $user['lastname'],
                'nickname' => $user['nickname'],
                'email' => $user['email'],
                'phone' => $user['phone'],
                'postcode' => $user['postcode'],
                'city' => $user['city'],
                'address_1' => $user['address_1'],
                'address_2' => $user['address_2'],
                'birthday' => $user['birthday'],
                'localGroup' => $user['localGroup'],
                'allergies' => $user['allergies'],
                'intolerances' => $user['intolerances'],
                'eating_habit' => $user['eating_habits'],
                'medications' => $user['medications'],
                'tetanusVaccination' => $user['tetanus_vaccination'],
            ];

        }


        $inertiaProvider = new InertiaProvider('Event/Signup', [
            'event' => $event,
            'availableEvents' => $availableEvents,
            'localGroups' => $event['contributingLocalGroups'],
            'participantData' => $participantData,
        ]);
        return $inertiaProvider->render();
    }

    public function signUp(int $eventId, Request $request) {
        $event = $this->events->getById($eventId, false);

        if (!$event->registration_allowed || new \DateTime() > $event->start_date) {
            return response()->json(['status' => 'closed'], 403);
        }

        $eventResource = $event->toResource();
        $registrationData = $request->input('registration_data');
        $siblingReduction = $registrationData['sibling'] === 'true';


        $arrival = \DateTime::createFromFormat('Y-m-d', $registrationData['arrival']);
        $departure = \DateTime::createFromFormat('Y-m-d', $registrationData['departure']);
        $tetanusVaccination = $registrationData['tetanusVaccination'] ? \DateTime::createFromFormat('Y-m-d', $registrationData['tetanusVaccination']) : null;

        $doubleCheckEventRegistrationProvider = new DoubleCheckEventRegistrationProvider(
            $event,
            $registrationData['vorname'],
            $registrationData['nachname'],
            $registrationData['email_1'],
            DateTime::createFromFormat('Y-m-d', $registrationData['geburtsdatum']));

            if ($doubleCheckEventRegistrationProvider->isRegistered()) {
                return response()->json(['status' => 'exists']);
            }

        $amount = $eventResource->calculateAmount(
            $registrationData['participationType'],
            $registrationData['beitrag'],
            $arrival,
            $departure,
            $siblingReduction
        );

        // Gewählte Zusätze (Event-Addons) auflösen und auf den Gesamtbetrag aufaddieren.
        $selectedAddonKeys = array_keys(array_filter((array)$request->input('addons', []), fn($v) => (bool)$v));
        $addonResolution = $eventResource->resolveAddons($selectedAddonKeys, $arrival, $departure);
        $amount->addAmount($addonResolution['total']);

        $signupRequest = new SignUpRequest(
            $event,
            $registrationData['userId'] ?? null,
            $registrationData['vorname'],
            $registrationData['nachname'],
            $registrationData['pfadiname'],
            $registrationData['participationType'],
            Tenant::findOrFail($registrationData['localGroup']),
            \DateTime::createFromFormat('Y-m-d', $registrationData['geburtsdatum']),
            $registrationData['address1'],
            $registrationData['address2'],
            $registrationData['plz'],
            $registrationData['ort'],
            $registrationData['email_1'],
            $registrationData['telefon_1'],
            $registrationData['email_2'],
            $registrationData['telefon_2'],
            $registrationData['ansprechpartner'],
            $registrationData['allergien'],
            $registrationData['intolerances'],
            $registrationData['medikamente'],
            $tetanusVaccination,
            $registrationData['essgewohnheit'],
            $registrationData['badeerlaubnis'],
            $registrationData['first_aid'],
            $registrationData['foto']['socialmedia'],
            $registrationData['foto']['print'],
            $registrationData['foto']['webseite'],
            $registrationData['foto']['partner'],
            $registrationData['foto']['intern'],
            $arrival,
            $departure,
            $registrationData['anreise_essen'],
            $registrationData['abreise_essen'],
            $registrationData['anmerkungen'],
            $amount,
            $registrationData['paymentMethod'] ?? null,
            (array)($registrationData['paymentOptions'] ?? []),
            (array)($registrationData['participationOptions'] ?? []),
            $addonResolution['items'],
        );

        $signupCommand = new SignUpCommand($signupRequest);
        $signupResponse = $signupCommand->execute();

        if (!$signupResponse->success) {
            return response()->json(['status' => 'error', 'message' => $signupResponse->message], 422);
        }

        // 4. Addons registrieren


        $certificateOfConductionCheckRequest = new CertificateOfConductionCheckRequest($signupResponse->participant);
        $certificateOfConductionCheckCommand = new CertificateOfConductionCheckCommand($certificateOfConductionCheckRequest);
        $certificateOfConductionCheckResponse = $certificateOfConductionCheckCommand->execute();

        $signupResponse->participant->efz_status = $certificateOfConductionCheckResponse->status;
        $signupResponse->participant->save();

        Mail::to($signupResponse->participant->email_1)->send(new EventSignUpSuccessfullMail(
            participant: $signupResponse->participant,
        ));

        if ($signupResponse->participant->email_2 !== null) {
            Mail::to($signupResponse->participant->email_2)->send(new EventSignUpSuccessfullMail(
                participant: $signupResponse->participant,
            ));
        }

        return response()->json(
            [
                'participant' => $signupResponse->participant->toResource()->toArray($request),
                'status' => 'success',
            ]
        );
    }

    public function calculateAmount(int $eventId, Request $request, bool $forDisplay = true) : JsonResponse | float {
        $event = $this->events->getById($eventId, false)->toResource();

        $siblingReduction = $request->input('sibling') === 'true';

        $arrival = \DateTime::createFromFormat('Y-m-d', $request->input('arrival'));
        $departure = \DateTime::createFromFormat('Y-m-d', $request->input('departure'));

        $baseFee = $event->calculateAmount(
            $request->input('participationType'),
            $request->input('beitrag'),
            $arrival,
            $departure,
            $siblingReduction
        );

        // Gewählte Zusätze immer einrechnen -- so enthält der finale Anzeigebetrag (und der Bestätigungstext)
        // stets die Addons und der Zahlungsschritt wird nur bei Gesamt 0 € übersprungen.
        $selectedAddonKeys = array_keys(array_filter((array)$request->input('addons', []), fn($v) => (bool)$v));
        $resolution = $event->resolveAddons($selectedAddonKeys, $arrival, $departure);

        // Gesamt = Teilnahmebeitrag + Zusätze; Basisbetrag separat für die Kostenübersicht in der Zusammenfassung.
        $total = new Amount($baseFee->getAmount(), 'Euro');
        $total->addAmount($resolution['total']);

        $addonLines = array_map(fn($item) => [
            'key' => $item['key'],
            'title' => $item['title'],
            'amountValue' => $item['amount'],
            'amount' => new Amount($item['amount'], 'Euro')->toString(),
            'free' => $item['amount'] <= 0,
        ], $resolution['items']);

        // amountValue (numerisch) steuert im Frontend das Überspringen des Zahlungsart-Schritts bei 0 €.
        return response()->json([
            'amount' => $total->toString(),
            'amountValue' => $total->getAmount(),
            'baseAmount' => $baseFee->toString(),
            'baseAmountValue' => $baseFee->getAmount(),
            'addons' => $addonLines,
        ]);
    }
}
