import json
from pathlib import Path
from typing import Any

from cryptography.fernet import Fernet


class EncryptedTokenStore:
    def __init__(self, root: Path) -> None:
        self.root: Path = root
        self.root.mkdir(parents=True, exist_ok=True)
        self._key_path: Path = self.root / ".key"

    def load(self, name: str) -> dict[str, Any] | None:
        token_path = self.root / f"{name}.enc"
        if not token_path.exists():
            return None
        fernet = Fernet(self._get_or_create_key())
        decrypted = fernet.decrypt(token_path.read_bytes())
        payload = json.loads(decrypted.decode("utf-8"))
        if isinstance(payload, dict):
            return payload
        msg = f"invalid token payload for {name}"
        raise RuntimeError(msg)

    def save(self, name: str, payload: dict[str, Any]) -> None:
        token_path = self.root / f"{name}.enc"
        fernet = Fernet(self._get_or_create_key())
        raw = json.dumps(payload, sort_keys=True).encode("utf-8")
        token_path.write_bytes(fernet.encrypt(raw))

    def delete(self, name: str) -> None:
        token_path = self.root / f"{name}.enc"
        if token_path.exists():
            token_path.unlink()

    def _get_or_create_key(self) -> bytes:
        if self._key_path.exists():
            return self._key_path.read_bytes()
        key = Fernet.generate_key()
        self._key_path.write_bytes(key)
        return key
