<?php

namespace App\Domains\Event\Actions\SetParticipationOptions;

use Illuminate\Support\Str;

class SetParticipationOptionsCommand
{
    public function __construct(private SetParticipationOptionsRequest $request)
    {
    }

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

        $this->request->event->participation_options = $this->normalize($this->request->questions);
        $this->request->event->save();

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

    /**
     * Normalisiert die rohe Fragen-Definition: trimmt Labels, generiert stabile Keys/Values und verwirft
     * unvollständige Fragen (kein Label oder keine gültige Option). Keys/Values sind innerhalb ihres
     * Geltungsbereichs eindeutig, damit Antworten robust referenzieren können.
     *
     * @param array<int, array<string, mixed>> $questions
     * @return array<int, array{key: string, title: string, label: string, options: array<int, array{value: string, label: string}>}>
     */
    private function normalize(array $questions): array
    {
        $normalized = [];
        $usedKeys = [];

        foreach ($questions as $question) {
            // Titel ist Pflicht (Überschrift/Feldbeschriftung); die Frage ist optionaler Erklärtext.
            $title = trim((string)($question['title'] ?? ''));
            if ($title === '') {
                continue;
            }

            $label = trim((string)($question['label'] ?? ''));

            $options = $this->normalizeOptions($question['options'] ?? []);
            if ($options === []) {
                continue;
            }

            $key = $this->uniqueSlug((string)($question['key'] ?? ''), $title, $usedKeys);
            $usedKeys[] = $key;

            $normalized[] = [
                'key' => $key,
                'title' => $title,
                'label' => $label,
                'options' => $options,
            ];
        }

        return $normalized;
    }

    /**
     * @param array<int, array<string, mixed>> $options
     * @return array<int, array{value: string, label: string}>
     */
    private function normalizeOptions(mixed $options): array
    {
        if (!is_array($options)) {
            return [];
        }

        $normalized = [];
        $usedValues = [];

        foreach ($options as $option) {
            $label = trim((string)($option['label'] ?? ''));
            if ($label === '') {
                continue;
            }

            $value = $this->uniqueSlug((string)($option['value'] ?? ''), $label, $usedValues);
            $usedValues[] = $value;

            $normalized[] = ['value' => $value, 'label' => $label];
        }

        return $normalized;
    }

    /**
     * Liefert einen eindeutigen Slug: bevorzugt den bestehenden Wert (Bestandsschutz für schon gespeicherte
     * Fragen/Antworten), sonst aus dem Label abgeleitet; Kollisionen werden durchnummeriert.
     *
     * @param array<int, string> $used
     */
    private function uniqueSlug(string $existing, string $label, array $used): string
    {
        $base = $existing !== '' ? $existing : Str::slug($label);
        if ($base === '') {
            $base = 'option';
        }

        $candidate = $base;
        $suffix = 2;
        while (in_array($candidate, $used, true)) {
            $candidate = $base . '-' . $suffix;
            $suffix++;
        }

        return $candidate;
    }
}
