<?php
// Change JWT_SECRET to a long random string before deploying.
define('JWT_SECRET', 'f0gHGG23#5j9gaGg90asndfa9gtybama89G#');
define('JWT_TTL', 60 * 60 * 24 * 30); // 30 days

class JWT {
    public static function encode(array $payload): string {
        $header  = self::b64e(json_encode(['alg' => 'HS256', 'typ' => 'JWT']));
        $payload['iat'] = time();
        $payload['exp'] = time() + JWT_TTL;
        $payload = self::b64e(json_encode($payload));
        $sig     = self::b64e(hash_hmac('sha256', "$header.$payload", JWT_SECRET, true));
        return "$header.$payload.$sig";
    }

    public static function decode(string $token): ?array {
        $parts = explode('.', $token);
        if (count($parts) !== 3) return null;
        [$header, $payload, $sig] = $parts;
        $expected = self::b64e(hash_hmac('sha256', "$header.$payload", JWT_SECRET, true));
        if (!hash_equals($expected, $sig)) return null;
        $data = json_decode(self::b64d($payload), true);
        if (!$data || ($data['exp'] ?? 0) < time()) return null;
        return $data;
    }

    private static function b64e(string $v): string {
        return rtrim(strtr(base64_encode($v), '+/', '-_'), '=');
    }

    private static function b64d(string $v): string {
        return base64_decode(strtr($v, '-_', '+/') . str_repeat('=', (4 - strlen($v) % 4) % 4));
    }
}
