from __future__ import annotations

"""Scriptable generator for producing encrypted licence files."""

import base64
import json
import secrets
from dataclasses import dataclass
from datetime import datetime, timezone
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 ..crypto_utils import derive_aes_key


@dataclass
class LicenceData:
    payload: dict
    signature: str


def generate_seed() -> str:
    return secrets.token_hex(32)


def encrypt_config(seed_hex: str, config: dict, hardware_fingerprint: str = "") -> dict:
    key = derive_aes_key(seed_hex, hardware_fingerprint)
    aesgcm = AESGCM(key)
    nonce = secrets.token_bytes(12)
    plaintext = json.dumps(config).encode("utf-8")
    ciphertext = aesgcm.encrypt(nonce, plaintext, None)
    return {
        "nonce": base64.b64encode(nonce).decode("utf-8"),
        "ciphertext": base64.b64encode(ciphertext[:-16]).decode("utf-8"),
        "tag": base64.b64encode(ciphertext[-16:]).decode("utf-8"),
    }


def sign_payload(payload: dict, private_key_path: Path) -> str:
    private_key = serialization.load_pem_private_key(private_key_path.read_bytes(), password=None)
    data = json.dumps(payload, sort_keys=True).encode("utf-8")
    signature = private_key.sign(data, padding.PKCS1v15(), hashes.SHA256())
    return base64.b64encode(signature).decode("utf-8")


def build_licence(config: dict, private_key_path: Path, hardware_fingerprint: str = "") -> LicenceData:
    seed = generate_seed()
    encrypted = encrypt_config(seed, config, hardware_fingerprint=hardware_fingerprint)

    payload = {
        "version": "2.0",
        "issuedDate": datetime.now(timezone.utc).isoformat(),
        "config": config,
        "encryption": {"seed": seed, **encrypted},
    }
    signature = sign_payload(payload, private_key_path)
    payload["signature"] = signature
    return LicenceData(payload, signature)


def write_licence_file(licence: LicenceData, output_path: Path) -> None:
    output_path.write_text(json.dumps(licence.payload, indent=2), encoding="utf-8")
