<?php
declare(strict_types=1);

class Rsvp
{
    private string $configFile;
    private string $sectionsFile;
    private string $languagesFile;

    public function __construct(string $dataDir)
    {
        $this->configFile    = $dataDir . '/config.json';
        $this->sectionsFile  = $dataDir . '/sections.json';
        $this->languagesFile = $dataDir . '/languages.json';
    }

    public function submit(array $input, Guests $guests): array
    {
        // Basic validation
        $name = trim(strip_tags($input['name'] ?? ''));
        if (!$name) throw new InvalidArgumentException('Name ist erforderlich');

        $rsvp = $input['rsvp'] ?? 'confirmed';
        if (!in_array($rsvp, ['confirmed', 'declined'], true)) {
            throw new InvalidArgumentException('Ungültiger RSVP-Status');
        }

        // Rate limiting: max 10 submissions per IP per hour
        $this->checkRateLimit();

        // Validate meal options against configured section
        $meal = $this->validateMeal((array)($input['meal'] ?? []));

        // Validate deadline
        $this->checkDeadline();

        $token = preg_replace('/[^a-f0-9]/', '', substr((string)($input['token'] ?? ''), 0, 16));

        $guest = $guests->upsertFromRsvp([
            'token'    => $token,
            'name'     => $name,
            'email'    => filter_var($input['email'] ?? '', FILTER_SANITIZE_EMAIL),
            'language' => $this->validateLanguage($input['language'] ?? ''),
            'persons'  => (int)($input['persons'] ?? 1),
            'rsvp'     => $rsvp,
            'meal'     => $meal,
            'message'  => strip_tags($input['message'] ?? ''),
        ]);

        return ['submitted' => true, 'rsvp' => $rsvp];
    }

    // ── Private ───────────────────────────────────────────────────────────────

    private function checkDeadline(): void
    {
        if (!file_exists($this->sectionsFile)) return;
        $sections = json_decode(file_get_contents($this->sectionsFile), true) ?? [];
        foreach ($sections as $s) {
            if ($s['type'] === 'rsvp' && !empty($s['data']['deadline'])) {
                if (strtotime($s['data']['deadline']) < time()) {
                    throw new RuntimeException('Die RSVP-Frist ist abgelaufen');
                }
                break;
            }
        }
    }

    private function validateMeal(array $meal): array
    {
        if (empty($meal)) return [];
        if (!file_exists($this->sectionsFile)) return [];

        $sections = json_decode(file_get_contents($this->sectionsFile), true) ?? [];
        $validOptions = [];
        foreach ($sections as $s) {
            if ($s['type'] === 'rsvp' && !empty($s['data']['meal_options'])) {
                foreach ($s['data']['meal_options'] as $opt) {
                    // collect all language values of the label
                    foreach ($opt as $k => $langData) {
                        if (is_array($langData) && isset($langData['label'])) {
                            $validOptions[] = strip_tags($langData['label']);
                        } elseif (is_string($langData)) {
                            $validOptions[] = strip_tags($langData);
                        }
                    }
                }
                break;
            }
        }

        if (empty($validOptions)) return array_map('strip_tags', $meal);

        return array_values(array_filter(
            array_map('strip_tags', $meal),
            fn($m) => in_array($m, $validOptions, true)
        ));
    }

    private function validateLanguage(string $lang): string
    {
        $lang = preg_replace('/[^a-z]/', '', strtolower($lang));
        if (!file_exists($this->languagesFile)) return $lang ?: 'de';
        $config = json_decode(file_get_contents($this->languagesFile), true) ?? [];
        $valid  = array_column($config['available'] ?? [], 'code');
        return in_array($lang, $valid, true) ? $lang : ($config['default'] ?? 'de');
    }

    private function checkRateLimit(): void
    {
        $ip      = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
        $key     = sys_get_temp_dir() . '/hw_rsvp_' . md5($ip) . '.json';
        $now     = time();
        $window  = 3600; // 1 hour
        $maxHits = 10;

        $data = [];
        if (file_exists($key)) {
            $data = json_decode(file_get_contents($key), true) ?? [];
        }

        // Remove old entries
        $data = array_filter($data, fn($t) => ($now - $t) < $window);
        $data = array_values($data);

        if (count($data) >= $maxHits) {
            throw new \OverflowException('Zu viele Anfragen. Bitte warte eine Stunde.');
        }

        $data[] = $now;
        file_put_contents($key, json_encode($data), LOCK_EX);
    }
}
