<?php

declare(strict_types=1);

/**
 * compensair-pay — front controller for the branded Stripe payment page (pay.compensair.com).
 *
 * PHP, no Node. Serves only read-only routes — PaymentIntents are created elsewhere
 * (EspoCRM via espocrm/StripeClient.php, or bin/create-link.php), the link is just
 * https://pay.compensair.com/p/<paymentIntentId>.
 *
 *   GET /p/{paymentIntentId}  branded payment page (Stripe Payment Element)
 *   GET /return               post-payment status page
 *   GET /health               {"ok":true}
 *   GET /robots.txt           Disallow: /
 *   GET /logo.png             logo (also embedded in the payment page)
 *   GET /.well-known/apple-developer-merchantid-domain-association  Apple Pay verification
 *
 * Every response: X-Robots-Tag noindex..., Referrer-Policy no-referrer, Cache-Control no-store.
 *
 * Web-server routing: nginx  -> try_files $uri /index.php$is_args$args;  (see deploy/nginx-php-fpm.conf)
 *                     Apache -> public/.htaccess rewrites everything here (see deploy/apache-vhost.conf)
 *
 * If you relocate this file away from <kit>/public/index.php, set BASE_DIR below to the kit root.
 */

namespace CompensairPay;

const BASE_DIR = __DIR__ . '/..';

require BASE_DIR . '/src/Config.php';
require BASE_DIR . '/src/Stripe.php';
require BASE_DIR . '/src/Pages.php';

const ROBOTS = 'noindex, nofollow, noarchive, nosnippet, noimageindex';

function noIndexHeaders(): void
{
    header('X-Robots-Tag: ' . ROBOTS);
    header('Referrer-Policy: no-referrer');
    header('Cache-Control: no-store');
}

/** @return never */
function send(int $status, string $body, string $contentType): void
{
    http_response_code($status);
    noIndexHeaders();
    header('Content-Type: ' . $contentType);
    header('X-Powered-By: '); // unset
    echo $body;
    exit;
}

/** @param array<string,mixed> $data  @return never */
function sendJson(int $status, array $data): void
{
    send($status, (string) json_encode($data), 'application/json');
}

/** @return never */
function sendHtml(int $status, string $body): void
{
    send($status, $body, 'text/html; charset=utf-8');
}

/** @return never */
function sendFile(string $path, string $contentType, ?string $cacheControl = null): void
{
    if (!is_file($path)) {
        sendHtml(404, Pages::htmlResult('Not found', 'Nothing to see here.'));
    }
    http_response_code(200);
    noIndexHeaders();
    header('Content-Type: ' . $contentType);
    if ($cacheControl !== null) {
        header('Cache-Control: ' . $cacheControl); // override no-store for static, immutable assets
    }
    readfile($path);
    exit;
}

$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$path   = rawurldecode((string) parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/');
$isRead = $method === 'GET' || $method === 'HEAD';
$assets = BASE_DIR . '/assets';

try {
    if ($isRead && $path === '/health') {
        sendJson(200, ['ok' => true]);
    }
    if ($isRead && $path === '/robots.txt') {
        send(200, "User-agent: *\nDisallow: /\n", 'text/plain; charset=utf-8');
    }
    if ($isRead && $path === '/logo.png') {
        sendFile($assets . '/logo.png', 'image/png', 'public, max-age=604800, immutable');
    }
    if ($isRead && $path === '/.well-known/apple-developer-merchantid-domain-association') {
        // Served verbatim; no no-index headers needed on this one (mirrors the Node version).
        if (!is_file($assets . '/apple-developer-merchantid-domain-association')) {
            http_response_code(404);
            exit;
        }
        http_response_code(200);
        header('Content-Type: application/octet-stream');
        readfile($assets . '/apple-developer-merchantid-domain-association');
        exit;
    }

    // Everything below needs Stripe config.
    $secretKey      = Config::require('STRIPE_SECRET_KEY');
    $publishableKey = Config::require('STRIPE_PUBLISHABLE_KEY');
    $currency       = strtolower((string) Config::get('CURRENCY', 'eur'));
    $productName    = (string) Config::get('PRODUCT_NAME', 'Compensair Services');
    $baseUrl        = rtrim((string) Config::get('PUBLIC_BASE_URL', 'https://pay.compensair.com'), '/');
    $stripe         = new Stripe($secretKey);

    if ($isRead && $path === '/return') {
        $piId = $_GET['payment_intent'] ?? '';
        if (!is_string($piId) || !preg_match('/^pi_[A-Za-z0-9]+$/', $piId)) {
            sendHtml(200, Pages::renderReturnPage('unknown', 0, $currency));
        }
        $r = $stripe->get('/v1/payment_intents/' . $piId);
        sendHtml(200, Pages::renderReturnPage(
            (string) ($r['data']['status'] ?? 'unknown'),
            (int) ($r['data']['amount'] ?? 0),
            (string) ($r['data']['currency'] ?? $currency)
        ));
    }

    if ($isRead && str_starts_with($path, '/p/')) {
        $id = substr($path, 3);
        if (!preg_match('/^pi_[A-Za-z0-9]+$/', $id)) {
            sendHtml(400, Pages::htmlResult('Invalid link', 'This payment link is malformed.'));
        }
        $r = $stripe->get('/v1/payment_intents/' . $id);
        if (!$r['ok'] || empty($r['data']['id']) || empty($r['data']['client_secret'])) {
            sendHtml(404, Pages::htmlResult('Link not found', 'This payment link is invalid or has expired.'));
        }
        if (($r['data']['status'] ?? '') === 'succeeded') {
            sendHtml(200, Pages::htmlResult('Already paid', 'This invoice was already paid. Thank you.'));
        }
        $d = $r['data'];
        sendHtml(200, Pages::renderPaymentPage([
            'clientSecret'   => (string) $d['client_secret'],
            'publishableKey' => $publishableKey,
            'amountCents'    => (int) ($d['amount'] ?? 0),
            'currency'       => (string) ($d['currency'] ?? $currency),
            'customerName'   => (string) ($d['metadata']['customerName'] ?? ''),
            'productName'    => (string) ($d['metadata']['productName'] ?? $productName),
            'returnUrl'      => $baseUrl . '/return',
        ]));
    }

    sendHtml(404, Pages::htmlResult('Not found', 'Nothing to see here.'));
} catch (\Throwable $e) {
    error_log('compensair-pay: ' . $e->getMessage());
    sendHtml(500, Pages::htmlResult('Error', 'Something went wrong. Please try again later.'));
}
