import base64
import hashlib
import hmac
import json
import os
import time
from cryptography.hazmat.primitives.ciphers.aead import AESGCM


def _b64(data):
    return base64.urlsafe_b64encode(data).decode().rstrip("=")


def _unb64(value):
    return base64.urlsafe_b64decode(value + "=" * (-len(value) % 4))


def create_token(subject, secret, ttl_seconds=43200):
    payload = {"sub": subject, "exp": int(time.time()) + ttl_seconds}
    body = _b64(json.dumps(payload, separators=(",", ":")).encode())
    signature = _b64(hmac.new(secret.encode(), body.encode(), hashlib.sha256).digest())
    return f"{body}.{signature}"


def verify_token(token, secret):
    try:
        body, signature = token.split(".", 1)
        expected = _b64(hmac.new(secret.encode(), body.encode(), hashlib.sha256).digest())
        if not hmac.compare_digest(signature, expected):
            return None
        payload = json.loads(_unb64(body))
        if int(payload["exp"]) < int(time.time()):
            return None
        return str(payload["sub"])
    except (ValueError, KeyError, TypeError, json.JSONDecodeError):
        return None


def _aes_key(secret):
    return hashlib.sha256(secret.encode()).digest()


def encrypt_text(value, secret):
    nonce = os.urandom(12)
    ciphertext = AESGCM(_aes_key(secret)).encrypt(nonce, value.encode(), None)
    return _b64(nonce + ciphertext)


def decrypt_text(value, secret):
    raw = _unb64(value)
    return AESGCM(_aes_key(secret)).decrypt(raw[:12], raw[12:], None).decode()


def hash_secret(value):
    return hashlib.sha256(value.encode()).hexdigest()
