<?php
/**
 * Forms — public-facing router.
 *
 * Wired by Forms::addPublicRoutes() — PublicRouter::dispatch() hands
 * us paths starting with /forms/. We render the form, accept POST,
 * and show a thanks page. `?embed=1` strips outer chrome for use
 * inside an iframe.
 *
 * URL shape:
 *   /forms/<slug>          → form (GET) + submit (POST)
 *   /forms/<slug>/thanks   → success page (after submit)
 */

if (!defined('SLATE_ROOT')) {
    require_once dirname(__DIR__, 3) . '/config.php';
}
require_once dirname(__DIR__) . '/FormsAPI.php';
FormsAPI::ensureSchema();

$path = trim((string)($_GET['_route_path'] ?? ''), '/');

// Split into <slug>[/<action>]
$segments = $path === '' ? [] : explode('/', $path);
$slug   = $segments[0] ?? '';
$action = $segments[1] ?? '';

$embed = !empty($_GET['embed']);

if ($slug === '') {
    forms_public_render_notfound('No form requested.', $embed);
    return;
}

$form = FormsAPI::getForm($slug);
if (!$form || $form['status'] !== 'published') {
    forms_public_render_notfound('That form isn\'t available.', $embed);
    return;
}

// Submission cap reached?
if (!empty($form['submission_limit']) && (int)$form['submission_limit'] > 0) {
    $count = (int) Database::value(
        "SELECT COUNT(*) FROM forms_submissions WHERE tenant_id = ? AND form_id = ?",
        [current_tenant_id(), (int)$form['id']]
    );
    if ($count >= (int)$form['submission_limit']) {
        forms_public_render_closed($form, $embed);
        return;
    }
}

// Thanks page
if ($action === 'thanks') {
    forms_public_render_thanks($form, $embed);
    return;
}

$errors = [];
$values = [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Honeypot — bots fill any input they see
    if (!empty($_POST['website_url'])) {
        // Pretend success, but never store.
        if (!empty($form['redirect_url'])) {
            header('Location: ' . $form['redirect_url']);
            exit;
        }
        forms_public_render_thanks($form, $embed);
        return;
    }

    if (!csrf_verify()) {
        $errors['_form'] = 'Security check failed. Please try again.';
    } elseif ((int) Database::value(
            "SELECT COUNT(*) FROM forms_submissions
              WHERE tenant_id = ? AND ip = ? AND created_at > (NOW() - INTERVAL 1 MINUTE)",
            [current_tenant_id(), FormsAPI::clientIp()]) >= 5) {
        // Rate limit per IP — blunts spam floods and the confirmation-email
        // amplification vector (the honeypot above only stops naive bots).
        $errors['_form'] = 'Too many submissions. Please wait a minute and try again.';
    } else {
        $result = FormsAPI::validateSubmission($form, $_POST);
        $values = $result['data'];

        // Handle file fields after text validation (cheap-fail order)
        if ($result['ok']) {
            $fileResult = FormsAPI::handleFileUploads($form, $result['data']);
            $result['data']   = $fileResult['data'];
            $result['errors'] = array_merge($result['errors'], $fileResult['errors']);
            $result['ok']     = empty($result['errors']);
            $values           = $result['data'];
        }

        if ($result['ok']) {
            $submissionId = forms_public_save_and_dispatch($form, $result['data']);
            if (!empty($form['redirect_url'])) {
                header('Location: ' . $form['redirect_url']);
                exit;
            }
            // Same-page success
            $thanksUrl = SLATE_URL . '/forms/' . $form['slug'] . '/thanks'
                       . ($embed ? '?embed=1' : '');
            header('Location: ' . $thanksUrl);
            exit;
        }
        $errors = $result['errors'];
    }
}

forms_public_render_form($form, $values, $errors, $embed);


// ─────────────────────────────────────────────────────────────
//                       Render helpers
// ─────────────────────────────────────────────────────────────

function forms_public_layout_start(string $title, bool $embed): void {
    $siteName = Database::setting('site_name') ?: 'Slate';
    slate_ui_emit_css();
    ?>
    <!DOCTYPE html>
    <html lang="<?= e(I18n::currentLocale()) ?>">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
        <title><?= e($title) ?> — <?= e($siteName) ?></title>
        <meta name="csrf" content="<?= e(csrf_token()) ?>">
        <link rel="stylesheet" href="<?= e(plugin_url('forms', 'assets/css/public.css')) ?>">
    </head>
    <body class="forms-public<?= $embed ? ' forms-public-embed' : '' ?>">
    <?php
}

function forms_public_layout_end(bool $embed): void {
    if (!$embed) {
        echo '<footer class="forms-public-footer text-sm text-muted text-center">Powered by '
           . e(Database::setting('site_name') ?: 'Slate') . '</footer>';
    }
    echo '</body></html>';
}

function forms_public_render_form(array $form, array $values, array $errors, bool $embed): void {
    forms_public_layout_start($form['title'], $embed);
    ?>
    <main class="forms-public-shell">
        <article class="forms-public-card">
            <header class="forms-public-header">
                <h1><?= e($form['title']) ?></h1>
                <?php if (!empty($form['description'])): ?>
                    <p class="forms-public-desc"><?= nl2br(e($form['description'])) ?></p>
                <?php endif; ?>
            </header>

            <?php if (!empty($errors['_form'])): ?>
                <div class="alert alert-error"><?= e($errors['_form']) ?></div>
            <?php elseif (!empty($errors)): ?>
                <div class="alert alert-error">Please fix the highlighted fields and try again.</div>
            <?php endif; ?>

            <form method="post" enctype="multipart/form-data" novalidate>
                <?= csrf_field() ?>
                <!-- Honeypot — hidden from humans, often filled by bots. -->
                <div style="position:absolute;left:-9999px;" aria-hidden="true">
                    <label>Website (leave blank)
                        <input type="text" name="website_url" tabindex="-1" autocomplete="off">
                    </label>
                </div>

                <?php foreach ($form['fields'] as $f):
                    $name  = $f['name'] ?? '';
                    $val   = $values[$name] ?? '';
                    $err   = $errors[$name] ?? null;
                    echo FormsAPI::renderField($f, $val, $err);
                endforeach; ?>

                <button type="submit" class="btn btn-primary btn-lg btn-block">
                    <?= e($form['submit_label'] ?: 'Submit') ?>
                </button>
            </form>
        </article>
    </main>
    <?php
    forms_public_layout_end($embed);
}

function forms_public_render_thanks(array $form, bool $embed): void {
    forms_public_layout_start('Thanks', $embed);
    $msg = $form['success_message'] ?: 'Thanks — we got your submission.';
    ?>
    <main class="forms-public-shell">
        <article class="forms-public-card forms-public-success">
            <div class="forms-public-success-icon" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
                     stroke-linecap="round" stroke-linejoin="round">
                    <polyline points="20 6 9 17 4 12"/>
                </svg>
            </div>
            <h1>Thanks!</h1>
            <p><?= nl2br(e($msg)) ?></p>
        </article>
    </main>
    <?php
    forms_public_layout_end($embed);
}

function forms_public_render_closed(array $form, bool $embed): void {
    forms_public_layout_start($form['title'], $embed);
    ?>
    <main class="forms-public-shell">
        <article class="forms-public-card">
            <h1><?= e($form['title']) ?></h1>
            <div class="alert alert-warning">
                This form has reached its submission limit and is no longer accepting entries.
            </div>
        </article>
    </main>
    <?php
    forms_public_layout_end($embed);
}

function forms_public_render_notfound(string $msg, bool $embed): void {
    http_response_code(404);
    forms_public_layout_start('Not found', $embed);
    ?>
    <main class="forms-public-shell">
        <article class="forms-public-card">
            <h1>Not found</h1>
            <p class="text-muted"><?= e($msg) ?></p>
        </article>
    </main>
    <?php
    forms_public_layout_end($embed);
}

// ─────────────────────────────────────────────────────────────
//                  Save + email + webhook
// ─────────────────────────────────────────────────────────────

function forms_public_save_and_dispatch(array $form, array $data): int {
    $tid = current_tenant_id();

    // Pull the submitter's email out for indexing
    $submitterEmail = null;
    foreach ($form['fields'] as $f) {
        if (($f['type'] ?? '') === 'email' && !empty($data[$f['name']]) && filter_var($data[$f['name']], FILTER_VALIDATE_EMAIL)) {
            $submitterEmail = $data[$f['name']];
            break;
        }
    }

    $ref = FormsAPI::generateRef();

    $emailSent  = 0;
    $emailError = null;

    // Admin notification (best-effort, errors recorded but not fatal)
    if (!empty($form['notify_email'])) {
        $body = forms_public_build_email_body($form, $data, $ref);
        $subj = 'New submission · ' . $form['title'] . ' (' . $ref . ')';
        try {
            $ok = Mailer::send($form['notify_email'], $subj, $body, '');
            $emailSent = $ok ? 1 : 0;
            if (!$ok) $emailError = 'Mailer::send returned false.';
        } catch (\Throwable $e) {
            $emailError = $e->getMessage();
        }
    }

    // Optional submitter confirmation
    if (!empty($form['confirm_submitter']) && $submitterEmail) {
        $confirmSubject = $form['confirm_subject'] ?: ('Thanks — ' . $form['title']);
        $confirmBody    = $form['confirm_body']    ?: ('<p>Thanks — we got your submission. Reference: <code>' . e($ref) . '</code>.</p>');
        try {
            Mailer::send($submitterEmail, $confirmSubject, $confirmBody, '');
        } catch (\Throwable $e) {
            // Don't fail the submit if the confirmation can't ship.
            slate_log('Forms: confirmation email failed: ' . $e->getMessage(), 'warning');
        }
    }

    $submissionId = Database::insert('forms_submissions', [
        'tenant_id'       => $tid,
        'form_id'         => (int)$form['id'],
        'ref'             => $ref,
        'data_json'       => json_encode($data, JSON_UNESCAPED_UNICODE),
        'submitter_email' => $submitterEmail,
        'ip'              => FormsAPI::clientIp(),
        'user_agent'      => mb_substr((string)($_SERVER['HTTP_USER_AGENT'] ?? ''), 0, 255),
        'email_sent'      => $emailSent,
        'email_error'     => $emailError,
    ]);

    AuditLog::record('forms.submitted', (string)$submissionId, [
        'form_id' => (int)$form['id'],
        'ref'     => $ref,
    ]);

    // Fire webhooks (best-effort, logged into forms_webhook_log)
    $payload = [
        'event'         => 'forms.submitted',
        'submission_id' => $submissionId,
        'ref'           => $ref,
        'form'          => [
            'id'    => (int)$form['id'],
            'slug'  => $form['slug'],
            'title' => $form['title'],
        ],
        'submitted_at'  => date('c'),
        'data'          => $data,
    ];
    FormsAPI::dispatchWebhooks((int)$form['id'], $submissionId, $payload);

    // Plugin extension point
    Hook::doAction('forms_submitted', (int)$submissionId, (int)$form['id'], $data);

    return $submissionId;
}

function forms_public_build_email_body(array $form, array $data, string $ref): string {
    $rows = '';
    foreach ($form['fields'] as $f) {
        $name  = $f['name']  ?? '';
        $label = $f['label'] ?? $name;
        if ($name === '') continue;
        $val = $data[$name] ?? '';
        if (is_bool($val)) $val = $val ? 'Yes' : 'No';
        if (is_array($val)) $val = implode(', ', array_map('strval', $val));
        $rows .= '<tr><td style="padding:6px 12px;border-bottom:1px solid #eee;color:#555;">'
              . e($label) . '</td><td style="padding:6px 12px;border-bottom:1px solid #eee;">'
              . nl2br(e((string)$val)) . '</td></tr>';
    }
    return '<p>New submission on <strong>' . e($form['title']) . '</strong> (' . e($ref) . ').</p>'
         . '<table style="border-collapse:collapse;font-family:sans-serif;font-size:14px;">'
         . $rows
         . '</table>'
         . '<p style="color:#888;font-size:12px;margin-top:24px;">Sent by Slate Forms.</p>';
}
