from __future__ import annotations

"""Utilities for handling RSA signature verification and symmetric decryption."""

import base64
import json
from dataclasses import dataclass
from hashlib import sha256
from typing import Any, Dict

from pathlib import Path

from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

from .embedded_keys import LICENCE_PUBLIC_KEY


@dataclass
class LicenceCryptoError(Exception):
    message: str


def load_public_key() -> serialization.PublicFormat:
    custom_key_path = Path.home() / ".web-sentinel" / "keys" / "license_public.pem"
    if custom_key_path.exists():
        pem_data = custom_key_path.read_bytes()
    else:
        pem_data = LICENCE_PUBLIC_KEY.encode("utf-8")
    return serialization.load_pem_public_key(pem_data)


def verify_signature(payload: Dict[str, Any], signature_b64: str) -> bool:
    data = json.dumps(payload, sort_keys=True).encode("utf-8")
    signature = base64.b64decode(signature_b64)
    public_key = load_public_key()
    try:
        public_key.verify(signature, data, padding.PKCS1v15(), hashes.SHA256())
        return True
    except Exception as exc:  # pragma: no cover - signature mismatch
        raise LicenceCryptoError(f"Signature validation failed: {exc}") from exc


def derive_aes_key(seed_hex: str, hardware_fingerprint: str) -> bytes:
    base_material = f"{seed_hex}:{hardware_fingerprint}".encode("utf-8")
    return sha256(base_material).digest()


def decrypt_payload(key: bytes, nonce_b64: str, ciphertext_b64: str, tag_b64: str) -> bytes:
    aesgcm = AESGCM(key)
    nonce = base64.b64decode(nonce_b64)
    ciphertext = base64.b64decode(ciphertext_b64)
    tag = base64.b64decode(tag_b64)
    combined = ciphertext + tag
    return aesgcm.decrypt(nonce, combined, None)
