<?php
declare(strict_types=1);

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

function respond(int $status, bool $success, string $message): never
{
    http_response_code($status);
    echo json_encode(
        ['success' => $success, 'message' => $message],
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
    );
    exit;
}

function enforceRateLimit(string $ip, string $fingerprint, int $now): void
{
    $storage = sys_get_temp_dir() . '/pwd-contact-' . hash('sha256', $ip . '|pacific-webdesign');
    $handle = fopen($storage, 'c+');
    if ($handle === false || !flock($handle, LOCK_EX)) {
        respond(503, false, 'La protection anti-spam est momentanément indisponible. Veuillez réessayer.');
    }

    $contents = stream_get_contents($handle);
    $state = json_decode($contents ?: '', true);
    if (!is_array($state)) {
        $state = ['attempts' => [], 'messages' => []];
    }

    $attempts = array_values(array_filter(
        is_array($state['attempts'] ?? null) ? $state['attempts'] : [],
        static fn ($timestamp): bool => is_int($timestamp) && $timestamp > ($now - 86400)
    ));
    $messages = is_array($state['messages'] ?? null) ? $state['messages'] : [];
    $messages = array_filter(
        $messages,
        static fn ($timestamp): bool => is_int($timestamp) && $timestamp > ($now - 86400)
    );

    $lastHour = count(array_filter(
        $attempts,
        static fn (int $timestamp): bool => $timestamp > ($now - 3600)
    ));

    if ($lastHour >= 3 || count($attempts) >= 8) {
        flock($handle, LOCK_UN);
        fclose($handle);
        respond(429, false, 'Trop de demandes ont été envoyées. Veuillez réessayer plus tard.');
    }

    if (isset($messages[$fingerprint])) {
        flock($handle, LOCK_UN);
        fclose($handle);
        respond(409, false, 'Cette demande a déjà été reçue. Il n’est pas nécessaire de la renvoyer.');
    }

    $attempts[] = $now;
    $messages[$fingerprint] = $now;
    $state = ['attempts' => $attempts, 'messages' => $messages];
    rewind($handle);
    ftruncate($handle, 0);
    fwrite($handle, json_encode($state, JSON_UNESCAPED_SLASHES));
    fflush($handle);
    flock($handle, LOCK_UN);
    fclose($handle);
}

function forgetFailedMessage(string $ip, string $fingerprint): void
{
    $storage = sys_get_temp_dir() . '/pwd-contact-' . hash('sha256', $ip . '|pacific-webdesign');
    $handle = fopen($storage, 'c+');
    if ($handle === false || !flock($handle, LOCK_EX)) {
        return;
    }

    $contents = stream_get_contents($handle);
    $state = json_decode($contents ?: '', true);
    if (is_array($state) && is_array($state['messages'] ?? null)) {
        unset($state['messages'][$fingerprint]);
        rewind($handle);
        ftruncate($handle, 0);
        fwrite($handle, json_encode($state, JSON_UNESCAPED_SLASHES));
        fflush($handle);
    }

    flock($handle, LOCK_UN);
    fclose($handle);
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Allow: POST');
    respond(405, false, 'Cette méthode n’est pas autorisée.');
}

$origin = (string) ($_SERVER['HTTP_ORIGIN'] ?? '');
if ($origin !== '') {
    $originHost = strtolower((string) parse_url($origin, PHP_URL_HOST));
    $allowedHosts = ['pacific-webdesign.com', 'www.pacific-webdesign.com', 'new.pacific-webdesign.com'];
    if (!in_array($originHost, $allowedHosts, true)) {
        respond(403, false, 'Cette demande ne provient pas du site officiel.');
    }
}

$contentLength = (int) ($_SERVER['CONTENT_LENGTH'] ?? 0);
if ($contentLength > 20000) {
    respond(413, false, 'Le message envoyé est trop volumineux.');
}

session_start();
$now = time();
$lastSubmission = (int) ($_SESSION['contact_last_submission'] ?? 0);
if ($lastSubmission > 0 && ($now - $lastSubmission) < 30) {
    respond(429, false, 'Veuillez patienter quelques secondes avant un nouvel envoi.');
}

$honeypot = trim((string) ($_POST['website'] ?? ''));
if ($honeypot !== '') {
    respond(200, true, 'Merci, votre demande a bien été envoyée.');
}

$formStarted = (int) ($_POST['form_started'] ?? 0);
$elapsed = $formStarted > 0 ? $now - (int) floor($formStarted / 1000) : 0;
if ($elapsed < 3 || $elapsed > 7200) {
    respond(200, true, 'Merci, votre demande a bien été envoyée.');
}

$name = trim((string) ($_POST['name'] ?? ''));
$email = trim((string) ($_POST['email'] ?? ''));
$project = trim((string) ($_POST['project'] ?? ''));
$message = trim((string) ($_POST['message'] ?? ''));

if ($name === '' || mb_strlen($name) > 100) {
    respond(422, false, 'Veuillez indiquer un nom valide.');
}

if (!filter_var($email, FILTER_VALIDATE_EMAIL) || mb_strlen($email) > 190) {
    respond(422, false, 'Veuillez indiquer une adresse e-mail valide.');
}

if ($project === '' || mb_strlen($project) > 120) {
    respond(422, false, 'Veuillez sélectionner un type de projet.');
}

if ($message === '' || mb_strlen($message) > 5000) {
    respond(422, false, 'Veuillez décrire votre projet en 5 000 caractères maximum.');
}

$linkCount = preg_match_all('/(?:https?:\\/\\/|www\\.)/iu', $message);
if ($linkCount !== false && $linkCount > 2) {
    respond(422, false, 'Votre message contient trop de liens. Retirez-en quelques-uns puis réessayez.');
}

$clientIp = (string) ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
$fingerprint = hash('sha256', mb_strtolower($email . '|' . $project . '|' . $message));
enforceRateLimit($clientIp, $fingerprint, $now);

$cleanName = preg_replace('/[\r\n]+/', ' ', $name) ?? $name;
$cleanEmail = str_replace(["\r", "\n"], '', $email);
$recipient = 'contact@pacific-webdesign.com';
$subject = 'Nouvelle demande — ' . $project;
$body = implode("\n", [
    'Nouvelle demande depuis pacific-webdesign.com',
    '',
    'Nom : ' . $cleanName,
    'E-mail : ' . $cleanEmail,
    'Projet : ' . $project,
    '',
    'Message :',
    $message,
    '',
    'Date : ' . date('d/m/Y H:i'),
]);

$headers = [
    'From: Pacific Webdesign <no-reply@pacific-webdesign.com>',
    'Reply-To: ' . $cleanName . ' <' . $cleanEmail . '>',
    'MIME-Version: 1.0',
    'Content-Type: text/plain; charset=UTF-8',
    'Content-Transfer-Encoding: 8bit',
];

$encodedSubject = '=?UTF-8?B?' . base64_encode($subject) . '?=';
$sent = mail($recipient, $encodedSubject, $body, implode("\r\n", $headers));

if (!$sent) {
    forgetFailedMessage($clientIp, $fingerprint);
    respond(500, false, 'L’envoi est momentanément indisponible. Vous pouvez nous contacter sur WhatsApp.');
}

$_SESSION['contact_last_submission'] = $now;
respond(200, true, 'Merci, votre demande a bien été envoyée. Nous vous répondrons rapidement.');
