<?php
declare(strict_types=1);

namespace PSLauncher\Routes;

use PSLauncher\Crypto;
use PSLauncher\Db;
use PSLauncher\Response;

/**
 * GET /api/download-url/{version}
 * Header : Authorization: Bearer <licenseKey>
 *
 * Vérifie la license, vérifie qu'elle autorise cette version (date d'entitlement
 * >= minLicenseDate), puis renvoie une URL HMAC-signée valide 1 h vers le ZIP
 * dans /builds/.
 */
final class DownloadUrl
{
    public static function handle(array $config, string $version): void
    {
        if (!preg_match('/^[0-9]+\.[0-9]+\.[0-9]+$/', $version)) {
            Response::error('invalid_version', 'Version invalide', 400);
        }

        // Auth via Authorization: Bearer <licenseKey>
        // Apache OVH (et autres hébergements FastCGI) strippe parfois le header. On
        // tente plusieurs sources :
        //  - $_SERVER['HTTP_AUTHORIZATION']         (cas standard)
        //  - $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] (mod_rewrite passthrough)
        //  - apache_request_headers()                (présent quand mod_php)
        //  - getallheaders()                          (idem)
        //  - ?key=...                                 (fallback explicite)
        $authHeader = $_SERVER['HTTP_AUTHORIZATION']
                   ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION']
                   ?? '';
        if ($authHeader === '' && function_exists('apache_request_headers')) {
            $h = apache_request_headers();
            $authHeader = $h['Authorization'] ?? $h['authorization'] ?? '';
        }
        if ($authHeader === '' && function_exists('getallheaders')) {
            $h = getallheaders();
            $authHeader = $h['Authorization'] ?? $h['authorization'] ?? '';
        }

        $licenseKey = '';
        if (preg_match('/^Bearer\s+(.+)$/i', $authHeader, $m)) {
            $licenseKey = trim($m[1]);
        } else {
            $licenseKey = trim((string)($_GET['key'] ?? ''));
        }
        if ($licenseKey === '') {
            Response::error('unauthorized',
                'License key requise (Authorization: Bearer ... ou ?key=...)', 401);
        }

        $db = Db::get($config);
        $stmt = $db->prepare(
            'SELECT id, owner_name, download_entitlement_until, revoked_at
             FROM licenses WHERE license_key = ? LIMIT 1'
        );
        $stmt->execute([$licenseKey]);
        $lic = $stmt->fetch();
        if (!$lic) {
            Response::error('invalid', 'License inconnue', 401);
        }
        if ($lic['revoked_at'] !== null) {
            Response::error('revoked', 'License révoquée', 403);
        }

        // Charge le manifest pour récupérer minLicenseDate de cette version
        $manifestPath = dirname(__DIR__, 2) . '/manifest/versions.json';
        if (!is_file($manifestPath)) {
            Response::error('manifest_missing', 'Manifest absent côté serveur', 500);
        }
        $manifest = json_decode(file_get_contents($manifestPath), true);
        $entry = null;
        foreach ($manifest['versions'] ?? [] as $v) {
            if (($v['version'] ?? '') === $version) { $entry = $v; break; }
        }
        if (!$entry) {
            Response::error('version_not_found', "Version {$version} absente du manifest", 404);
        }

        // Vérif droits téléchargement
        $entUntil = strtotime($lic['download_entitlement_until']);
        $minDate  = isset($entry['minLicenseDate']) ? strtotime($entry['minLicenseDate']) : 0;
        if ($minDate > 0 && $entUntil < $minDate) {
            Response::error('entitlement_expired',
                'Cette license n\'autorise pas cette version (date d\'expiration trop ancienne)',
                403,
                [
                    'entitlementUntil' => date(\DateTimeInterface::ATOM, $entUntil),
                    'minLicenseDate'   => date(\DateTimeInterface::ATOM, $minDate),
                ]);
        }

        // Génère l'URL HMAC-signée
        // TTL : 6 h. Compromis entre :
        //  - sécurité (limite la fenêtre de replay si une URL fuit)
        //  - utilisabilité (un user en ADSL 8 Mbps mettra ~4 h pour DL 14 Go)
        // Pour une connexion plus lente, le client sait auto-refresher l'URL
        // pendant le DL (cf DownloadManager → 403 retry avec nouvelle URL).
        $baseUrl  = rtrim($config['base_url'], '/');
        $relPath  = '/builds/proserve-' . $version . '.zip';
        $exp      = time() + 21600; // 6 h
        $secret   = $config['hmac_secret'] ?? '';
        if ($secret === '') {
            Response::error('config_error', 'hmac_secret non configuré', 500);
        }
        $sigInput = $relPath . '|' . $exp . '|' . $lic['id'];
        $sig      = Crypto::hmacHex($sigInput, $secret);

        $signedUrl = $baseUrl . $relPath . '?exp=' . $exp . '&lic=' . $lic['id'] . '&sig=' . $sig;

        // Audit
        try {
            $db->prepare(
                'INSERT INTO audit_log (ts, license_id, ip, event, detail) VALUES (NOW(), ?, ?, ?, ?)'
            )->execute([
                $lic['id'],
                $_SERVER['REMOTE_ADDR'] ?? null,
                'download_url_issued',
                json_encode(['version' => $version], JSON_UNESCAPED_UNICODE),
            ]);
        } catch (\Throwable) { /* best-effort */ }

        Response::json([
            'url'       => $signedUrl,
            'expiresAt' => date(\DateTimeInterface::ATOM, $exp),
            'sizeBytes' => $entry['download']['sizeBytes'] ?? 0,
            'sha256'    => $entry['download']['sha256'] ?? '',
        ]);
    }
}
