<?php
declare(strict_types=1);

class Geschenketisch
{
    private string $sectionsFile;
    private string $configFile;

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

    /**
     * Reserve a gift item. Validates availability, updates sections.json,
     * sends emails (respecting surprise_mode).
     */
    public function reserve(array $input): array
    {
        // Honeypot check
        if (!empty($input['_hp'])) {
            throw new InvalidArgumentException('Ungültige Anfrage');
        }

        $sectionId = trim(strip_tags($input['section_id'] ?? ''));
        $itemIndex = (int)($input['item_index'] ?? -1);
        $name      = trim(strip_tags($input['name']  ?? ''));
        $email     = trim(filter_var($input['email'] ?? '', FILTER_SANITIZE_EMAIL));

        if (!$sectionId) throw new InvalidArgumentException('section_id fehlt');
        if ($itemIndex < 0) throw new InvalidArgumentException('item_index fehlt');
        if (!$name)  throw new InvalidArgumentException('Name ist erforderlich');
        if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Gültige E-Mail-Adresse erforderlich');
        }

        $this->checkRateLimit();

        $sections = $this->loadSections();
        $sIdx     = null;
        foreach ($sections as $i => $s) {
            if ($s['id'] === $sectionId && $s['type'] === 'geschenketisch') {
                $sIdx = $i;
                break;
            }
        }
        if ($sIdx === null) throw new RuntimeException('Abschnitt nicht gefunden');

        $items = $sections[$sIdx]['data']['items'] ?? [];
        if (!isset($items[$itemIndex])) throw new RuntimeException('Geschenk nicht gefunden');

        $item = $items[$itemIndex];
        if (($item['status'] ?? 'available') !== 'available') {
            throw new RuntimeException('Dieses Geschenk ist bereits reserviert');
        }

        // Update item
        $sections[$sIdx]['data']['items'][$itemIndex]['status']     = 'reserved';
        $sections[$sIdx]['data']['items'][$itemIndex]['giver_name'] = $name;
        $sections[$sIdx]['data']['items'][$itemIndex]['giver_email'] = $email;

        $this->saveSections($sections);

        $surpriseMode = (bool)($sections[$sIdx]['data']['surprise_mode'] ?? false);
        $giftTitle    = is_array($item['title'] ?? null)
            ? ($item['title']['de'] ?? reset($item['title']) ?? '')
            : ($item['title'] ?? '');

        $this->sendCoupleNotification($giftTitle, $name, $surpriseMode);
        $this->sendGuestConfirmation($email, $name, $giftTitle);

        return ['reserved' => true];
    }

    /**
     * Admin: update status and/or giver_name of a single gift item.
     */
    public function updateItem(string $sectionId, int $itemIndex, array $input): array
    {
        $sections = $this->loadSections();
        $sIdx = null;
        foreach ($sections as $i => $s) {
            if ($s['id'] === $sectionId && $s['type'] === 'geschenketisch') { $sIdx = $i; break; }
        }
        if ($sIdx === null) throw new RuntimeException('Abschnitt nicht gefunden');
        if (!isset($sections[$sIdx]['data']['items'][$itemIndex])) throw new RuntimeException('Geschenk nicht gefunden');

        if (array_key_exists('status', $input)) {
            $status = $input['status'];
            if (!in_array($status, ['available', 'reserved'], true)) throw new InvalidArgumentException('Ungültiger Status');
            $sections[$sIdx]['data']['items'][$itemIndex]['status'] = $status;
            if ($status === 'available') {
                unset($sections[$sIdx]['data']['items'][$itemIndex]['giver_name']);
                unset($sections[$sIdx]['data']['items'][$itemIndex]['giver_email']);
            }
        }
        if (array_key_exists('giver_name', $input)) {
            $sections[$sIdx]['data']['items'][$itemIndex]['giver_name'] = trim(strip_tags($input['giver_name'] ?? ''));
        }

        $this->saveSections($sections);
        return $sections[$sIdx]['data']['items'][$itemIndex];
    }

    /**
     * Returns items for a specific section, with giver_name optionally anonymized.
     * Used by the frontend section component via window.D (PHP renders this at page load).
     */
    public static function filterItemsForPublic(array $sectionData): array
    {
        $surpriseMode = (bool)($sectionData['surprise_mode'] ?? false);
        $items = $sectionData['items'] ?? [];

        return array_map(function ($item) use ($surpriseMode) {
            $filtered = [
                'title'  => $item['title']  ?? '',
                'link'   => $item['link']   ?? '',
                'status' => $item['status'] ?? 'available',
            ];
            // Include i18n language sub-objects (e.g. de.note, en.note)
            foreach ($item as $key => $value) {
                if (is_array($value) && preg_match('/^[a-z]{2}$/', $key)) {
                    $filtered[$key] = $value;
                }
            }
            // Only expose giver_name to browser if surprise mode is OFF
            if (!$surpriseMode && !empty($item['giver_name'])) {
                $filtered['giver_name'] = $item['giver_name'];
            }
            return $filtered;
        }, $items);
    }

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

    private function loadSections(): array
    {
        if (!file_exists($this->sectionsFile)) return [];
        return json_decode(file_get_contents($this->sectionsFile), true) ?? [];
    }

    private function saveSections(array $sections): void
    {
        $tmp = $this->sectionsFile . '.tmp';
        file_put_contents($tmp, json_encode($sections, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), LOCK_EX);
        if (!rename($tmp, $this->sectionsFile)) {
            @unlink($tmp);
            throw new RuntimeException('Konnte Daten nicht speichern');
        }
    }

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

        $times = file_exists($key) ? (json_decode(file_get_contents($key), true) ?? []) : [];
        $times = array_filter($times, fn($t) => ($now - $t) < $window);
        if (count($times) >= $max) {
            throw new RuntimeException('Zu viele Anfragen. Bitte versuche es später erneut.');
        }
        $times[] = $now;
        file_put_contents($key, json_encode(array_values($times)), LOCK_EX);
    }

    private function sendCoupleNotification(string $giftTitle, string $guestName, bool $surpriseMode): void
    {
        if (!file_exists($this->configFile)) return;
        $cfg = json_decode(file_get_contents($this->configFile), true) ?? [];
        if (empty($cfg['smtp_host']) || empty($cfg['from_email'])) return;

        try {
            require_once __DIR__ . '/SmtpMailer.php';
            $mailer  = new SmtpMailer($cfg);
            $toEmail = $cfg['from_email'];
            $toName  = $cfg['from_name'] ?? '';

            if ($surpriseMode) {
                $subject = 'Ein Geschenk von eurer Liste wurde reserviert!';
                $html    = '<!DOCTYPE html><html><body style="font-family:sans-serif;">'
                    . '<h2>Neue Reservierung 🎁</h2>'
                    . '<p>Ein Geschenk von eurer Wunschliste wurde gerade reserviert!</p>'
                    . '<p>Loggt euch nach der Hochzeit ein, um zu sehen, von wem.</p>'
                    . '</body></html>';
            } else {
                $subject = $guestName . ' hat "' . $giftTitle . '" reserviert';
                $html    = '<!DOCTYPE html><html><body style="font-family:sans-serif;">'
                    . '<h2>Neue Reservierung 🎁</h2>'
                    . '<p><strong>' . htmlspecialchars($guestName) . '</strong> hat gerade '
                    . '<strong>' . htmlspecialchars($giftTitle) . '</strong> von eurer Liste gewählt.</p>'
                    . '</body></html>';
            }

            $mailer->send($toEmail, $toName, $subject, $html);
        } catch (Throwable) {
            error_log('[HW Geschenketisch] Couple notification failed');
        }
    }

    private function sendGuestConfirmation(string $email, string $name, string $giftTitle): void
    {
        if (!file_exists($this->configFile)) return;
        $cfg = json_decode(file_get_contents($this->configFile), true) ?? [];
        if (empty($cfg['smtp_host'])) return;

        try {
            require_once __DIR__ . '/SmtpMailer.php';
            $mailer  = new SmtpMailer($cfg);
            $subject = 'Deine Reservierung: ' . $giftTitle;
            $html    = '<!DOCTYPE html><html><body style="font-family:sans-serif;">'
                . '<h2>Danke für deine Reservierung!</h2>'
                . '<p>Hallo ' . htmlspecialchars($name) . ',</p>'
                . '<p>du hast <strong>' . htmlspecialchars($giftTitle) . '</strong> für das Brautpaar reserviert. Vielen Dank!</p>'
                . '</body></html>';

            $mailer->send($email, $name, $subject, $html);
        } catch (Throwable) {
            error_log('[HW Geschenketisch] Guest confirmation failed');
        }
    }
}
