# #region EncryptionKeyModule [C:5] [TYPE Module] [SEMANTICS encryption, fernet, key, env, secret]
# @BRIEF Resolve a Fernet encryption key from environment or .env file.
# @LAYER Infrastructure
# @RELATION DEPENDS_ON -> [LoggerModule]
# @INVARIANT Runtime key resolution never falls back to an auto-generated key.
#            If no key is found in env or .env, the application crashes early.
# @PRE ENCRYPTION_KEY is set in process environment or .env file.
# @POST A valid Fernet key is returned and set in process environment.
# @SIDE_EFFECT Sets os.environ["ENCRYPTION_KEY"] if loaded from .env file.
# @DATA_CONTRACT Input[env_file_path] -> Output[encryption_key]
# @RATIONALE Auto-generating a key on first run is dangerous — the key differs
#            per deployment, making encrypted data unrecoverable on restart.
#            Crash-early forces the admin to explicitly set ENCRYPTION_KEY.
# @REJECTED Auto-generation rejected — encrypted data becomes unrecoverable
#           when the key changes between deployments (see [SEC:H-3]).

from __future__ import annotations

import os
from pathlib import Path

from cryptography.fernet import Fernet

from .logger import belief_scope, logger

DEFAULT_ENV_FILE_PATH = Path(__file__).resolve().parents[2] / ".env"


# #region ensure_encryption_key [TYPE Function]
# @BRIEF Ensure backend runtime has a persistent valid Fernet key.
# @PRE ENCRYPTION_KEY is set in process environment or backend/.env file.
# @POST Returns a valid Fernet key and sets it in process environment.
# @SIDE_EFFECT Sets os.environ["ENCRYPTION_KEY"] if loaded from .env file.
# @RAISES RuntimeError if no ENCRYPTION_KEY is found anywhere.
def ensure_encryption_key(env_file_path: Path = DEFAULT_ENV_FILE_PATH) -> str:
    with belief_scope("ensure_encryption_key", f"env_file_path={env_file_path}"):

        # 1. Check process environment
        existing_key = os.getenv("ENCRYPTION_KEY", "").strip()
        if existing_key:
            Fernet(existing_key.encode())
            logger.reason("Using ENCRYPTION_KEY from process environment.")
            return existing_key

        # 2. Check .env file
        if env_file_path.exists():
            for raw_line in env_file_path.read_text(encoding="utf-8").splitlines():
                if raw_line.startswith("ENCRYPTION_KEY="):
                    persisted_key = raw_line.partition("=")[2].strip()
                    if persisted_key:
                        Fernet(persisted_key.encode())
                        os.environ["ENCRYPTION_KEY"] = persisted_key
                        logger.reason(f"Loaded ENCRYPTION_KEY from {env_file_path}.")
                        return persisted_key

        # 3. Crash-early — no auto-generation (see [SEC:H-3])
        logger.explore(
            "No ENCRYPTION_KEY found in environment or .env file. "
            "Generate one with: python -c \"from cryptography.fernet import Fernet; "
            "print(Fernet.generate_key().decode())\" and set it in .env or export it."
        )
        raise RuntimeError(
            "ENCRYPTION_KEY is not set. "
            "Generate a key and add it to your .env file:\n"
            "  python -c \"from cryptography.fernet import Fernet; "
            "print(Fernet.generate_key().decode())\""
        )


# #endregion ensure_encryption_key

# #endregion EncryptionKeyModule
