<?php
declare(strict_types=1);

ini_set('display_errors', '0');

require_once __DIR__ . '/../includes/config.php';
require_once __DIR__ . '/../includes/db.php';

header('Content-Type: application/json; charset=utf-8');
header('X-Content-Type-Options: nosniff');

function fail(string $code, int $status = 400)
{
    http_response_code($status);
    echo json_encode(['ok' => false, 'error' => $code]);
    exit;
}

if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
    fail('method', 405);
}

if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

// CSRF
$csrf = (string) ($_POST['csrf'] ?? '');
if (empty($_SESSION['csrf']) || !hash_equals($_SESSION['csrf'], $csrf)) {
    fail('csrf', 419);
}

// Honeypot: a real guest never fills this field.
if (trim((string) ($_POST['website'] ?? '')) !== '') {
    fail('spam', 422);
}

// ---- Read and clean input ---------------------------------------------------
$fullName = trim((string) ($_POST['full_name'] ?? ''));
$fullName = preg_replace('/\s+/u', ' ', $fullName);
$iso      = strtoupper(substr(trim((string) ($_POST['country_iso'] ?? '')), 0, 2));
$code     = trim((string) ($_POST['country_code'] ?? ''));
$phoneRaw = preg_replace('/[^0-9]/', '', (string) ($_POST['phone'] ?? ''));
$attend   = (string) ($_POST['attending'] ?? '');
$lang     = ((string) ($_POST['lang'] ?? 'fr')) === 'en' ? 'en' : 'fr';

if (mb_strlen($fullName) < 3 || mb_strlen($fullName) > 120) {
    fail('name');
}
if (!preg_match('/^[\p{L}][\p{L}\s\'’.\-]{2,}$/u', $fullName)) {
    fail('name');
}
if ($attend !== '0' && $attend !== '1') {
    fail('attending');
}

// The country must exist in our own list.
$countries = require __DIR__ . '/../includes/countries.php';
$match = null;
foreach ($countries as $row) {
    if ($row[0] === $iso) {
        $match = $row;
        break;
    }
}
if ($match === null) {
    fail('country');
}
$code = $match[1];

$national = ltrim($phoneRaw, '0');
if (strlen($national) < 6 || strlen($national) > 15) {
    fail('phone');
}

$e164 = $code . $national;
if (strlen($e164) > 24) {
    fail('phone');
}

$ip = client_ip();
$ua = substr((string) ($_SERVER['HTTP_USER_AGENT'] ?? ''), 0, 255);
$now = date('Y-m-d H:i:s');

try {
    $pdo = db();

    // ---- Rate limit by address ----------------------------------------------
    $stmt = $pdo->prepare('SELECT last_submit, hits FROM submit_log WHERE ip_address = ?');
    $stmt->execute([$ip]);
    $log = $stmt->fetch();

    if ($log) {
        $insideWindow = (time() - strtotime((string) $log['last_submit'])) < SUBMIT_WINDOW_SECONDS;
        if ($insideWindow && (int) $log['hits'] >= SUBMIT_MAX_PER_WINDOW) {
            fail('throttle', 429);
        }
        $hits = $insideWindow ? (int) $log['hits'] + 1 : 1;
        $pdo->prepare('UPDATE submit_log SET last_submit = ?, hits = ? WHERE ip_address = ?')
            ->execute([$now, $hits, $ip]);
    } else {
        $pdo->prepare('INSERT INTO submit_log (ip_address, last_submit, hits) VALUES (?, ?, 1)')
            ->execute([$ip, $now]);
    }

    // ---- Upsert the answer --------------------------------------------------
    $stmt = $pdo->prepare('SELECT id FROM rsvps WHERE phone_e164 = ?');
    $stmt->execute([$e164]);
    $existing = $stmt->fetchColumn();

    if ($existing !== false) {
        $pdo->prepare(
            'UPDATE rsvps
                SET full_name = ?, country_iso = ?, country_code = ?, phone = ?,
                    attending = ?, lang = ?, ip_address = ?, user_agent = ?, updated_at = ?
              WHERE id = ?'
        )->execute([
            $fullName, $iso, $code, $national, (int) $attend, $lang, $ip, $ua, $now, (int) $existing,
        ]);
        echo json_encode(['ok' => true, 'updated' => true]);
        exit;
    }

    $pdo->prepare(
        'INSERT INTO rsvps
            (full_name, country_iso, country_code, phone, phone_e164, attending, lang, ip_address, user_agent, created_at)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
    )->execute([
        $fullName, $iso, $code, $national, $e164, (int) $attend, $lang, $ip, $ua, $now,
    ]);

    echo json_encode(['ok' => true, 'updated' => false]);
} catch (Throwable $err) {
    error_log('[pko50] ' . $err->getMessage());
    fail('server', 500);
}
