<?php
declare(strict_types=1);

class Kuchenliste
{
    private string $file;
    private string $configFile;

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

    // ── Public submit (with spam protection) ─────────────────────────────────

    public function submit(array $input): array
    {
        // Honeypot field check
        if (!empty($input['_hp'])) {
            throw new InvalidArgumentException('Ungültige Anfrage');
        }

        $name      = trim(strip_tags($input['name']      ?? ''));
        $kuchen    = trim(strip_tags($input['kuchen']    ?? ''));
        $anmerkung = trim(strip_tags($input['anmerkung'] ?? ''));
        $sectionId = trim(strip_tags($input['section_id'] ?? ''));
        if ($sectionId && !preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i', $sectionId)) {
            $sectionId = '';
        }

        if (!$name)   throw new InvalidArgumentException('Name ist erforderlich');
        if (!$kuchen) throw new InvalidArgumentException('Kuchen ist erforderlich');

        $this->checkRateLimit();

        $entry = [
            'id'           => $this->uuid(),
            'section_id'   => $sectionId,
            'name'         => $name,
            'kuchen'       => $kuchen,
            'anmerkung'    => $anmerkung,
            'submitted_at' => date('c'),
        ];

        $entries   = $this->load();
        $entries[] = $entry;
        $this->save($entries);

        $this->sendNotification($entry);

        return ['submitted' => true];
    }

    // ── Admin CRUD ────────────────────────────────────────────────────────────

    public function getAll(): array
    {
        return $this->load();
    }

    public function update(string $id, array $input): array
    {
        $entries = $this->load();
        foreach ($entries as &$e) {
            if ($e['id'] === $id) {
                if (isset($input['name']))   $e['name']   = strip_tags($input['name']);
                if (isset($input['kuchen'])) $e['kuchen'] = strip_tags($input['kuchen']);
                if (isset($input['anmerkung'])) $e['anmerkung'] = strip_tags($input['anmerkung']);
                $this->save($entries);
                return $e;
            }
        }
        throw new RuntimeException('Eintrag nicht gefunden');
    }

    public function delete(string $id): void
    {
        $entries = array_values(array_filter($this->load(), fn($e) => $e['id'] !== $id));
        $this->save($entries);
    }

    // ── Public list (name + kuchen only, no anmerkung) ───────────────────────

    public function getPublic(): array
    {
        return array_map(fn($e) => [
            'name'   => $e['name'],
            'kuchen' => $e['kuchen'],
        ], $this->load());
    }

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

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

    private function save(array $entries): void
    {
        $tmp = $this->file . '.tmp';
        file_put_contents($tmp, json_encode($entries, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), LOCK_EX);
        if (!rename($tmp, $this->file)) {
            @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_kuchen_' . md5($ip) . '.json';
        $now    = time();
        $window = 3600;
        $max    = 5;

        $times = [];
        if (file_exists($key)) {
            $times = 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 Einreichungen. Bitte versuche es später erneut.');
        }
        $times[] = $now;
        file_put_contents($key, json_encode(array_values($times)), LOCK_EX);
    }

    private function sendNotification(array $entry): 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'] ?? '';
            $subject = 'Neue Kucheneinreichung: ' . $entry['name'];

            $anmerkungHtml = $entry['anmerkung']
                ? '<p><strong>Anmerkung:</strong> ' . nl2br(htmlspecialchars($entry['anmerkung'])) . '</p>'
                : '';

            $html = '<!DOCTYPE html><html><body style="font-family:sans-serif;">'
                . '<h2>Neue Kucheneinreichung</h2>'
                . '<p><strong>Name:</strong> ' . htmlspecialchars($entry['name']) . '</p>'
                . '<p><strong>Kuchen:</strong> ' . htmlspecialchars($entry['kuchen']) . '</p>'
                . $anmerkungHtml
                . '</body></html>';

            $mailer->send($toEmail, $toName, $subject, $html);
        } catch (Throwable) {
            // Non-fatal — submission was saved, mail failure is logged
            error_log('[HW Kuchenliste] Mail send failed for entry ' . $entry['id']);
        }
    }

    private function uuid(): string
    {
        $b = random_bytes(16);
        $b[6] = chr(ord($b[6]) & 0x0f | 0x40);
        $b[8] = chr(ord($b[8]) & 0x3f | 0x80);
        return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($b), 4));
    }
}
