#!/usr/bin/env python3
"""Helper to get encryption key from Infisical and encrypt credentials before emission."""

import subprocess
import json
import logging
from typing import Optional

logger = logging.getLogger(__name__)

# Cache the key in memory during module lifetime
_cached_key: Optional[bytes] = None

def get_credential_encryption_key() -> Optional[bytes]:
    """Retrieve credential encryption key from Infisical via creds CLI.
    
    Returns None if key cannot be retrieved (in which case plaintext fallback).
    Caches key in memory for the lifetime of the module process.
    """
    global _cached_key
    if _cached_key is not None:
        return _cached_key
    
    try:
        import os
        creds_bin = os.environ.get("BB_CREDS_BIN")
        if not creds_bin:
            raise FileNotFoundError(
                "BB_CREDS_BIN environment variable not set. "
                "Set it to the path of your Infisical creds CLI binary, e.g. "
                "export BB_CREDS_BIN=/usr/local/bin/creds"
            )
        # Try to get CREDENTIAL_ENCRYPTION_KEY from Infisical via creds CLI
        result = subprocess.run(
            [creds_bin, "get", "CREDENTIAL_ENCRYPTION_KEY"],
            capture_output=True,
            timeout=5,
            text=True,
        )
        
        if result.returncode != 0:
            logger.warning("Failed to retrieve CREDENTIAL_ENCRYPTION_KEY from Infisical: %s", result.stderr)
            return None
        
        key_hex = result.stdout.strip()
        if not key_hex:
            logger.warning("CREDENTIAL_ENCRYPTION_KEY is empty in Infisical")
            return None
        
        # Convert hex string to bytes
        _cached_key = bytes.fromhex(key_hex)
        if len(_cached_key) != 32:
            logger.error("CREDENTIAL_ENCRYPTION_KEY must be 32 bytes (256-bit), got %d", len(_cached_key))
            _cached_key = None
            return None
        
        logger.debug("Successfully loaded CREDENTIAL_ENCRYPTION_KEY from Infisical")
        return _cached_key
        
    except FileNotFoundError:
        logger.error("creds CLI not found at ~/.local/bin/creds")
        return None
    except subprocess.TimeoutExpired:
        logger.error("Timeout retrieving CREDENTIAL_ENCRYPTION_KEY from Infisical")
        return None
    except Exception as e:
        logger.error("Error retrieving CREDENTIAL_ENCRYPTION_KEY: %s", e)
        return None


def emit_credential_found(bus, source_module: str, payload: dict) -> None:
    """Emit CREDENTIAL_FOUND event with encrypted sensitive fields.
    
    Sensitive fields are encrypted before emission. If encryption fails,
    plaintext fallback is used with a warning logged.
    
    Args:
        bus: EventBus instance
        source_module: Module name emitting the event
        payload: Credential payload dict with fields like username, password, etc.
    """
    from utils.crypto import encrypt_credential_dict
    
    key = get_credential_encryption_key()
    
    if key:
        try:
            encrypted_payload = encrypt_credential_dict(payload, key)
            bus.emit("CREDENTIAL_FOUND", encrypted_payload, source_module=source_module)
            return
        except Exception as e:
            logger.warning("Failed to encrypt credential payload: %s — using plaintext fallback", e)
    
    # Fallback: emit plaintext with warning
    bus.emit("CREDENTIAL_FOUND", payload, source_module=source_module)


def decrypt_credential_payload(payload: dict) -> dict:
    """Decrypt sensitive fields in credential event payload.
    
    Looks for fields marked with __encrypted__ prefix and decrypts them.
    Returns a new dict with decrypted fields.
    
    Args:
        payload: Credential dict with possibly encrypted fields
        
    Returns:
        New dict with decrypted values
    """
    from utils.crypto import decrypt_credential_field
    
    key = get_credential_encryption_key()
    if not key:
        return payload
    
    decrypted = {}
    
    for field, value in payload.items():
        if isinstance(value, str) and value.startswith("__encrypted__"):
            try:
                decrypted[field] = decrypt_credential_field(value, key)
            except Exception as e:
                logger.warning("Failed to decrypt field %s: %s", field, e)
                decrypted[field] = value
        else:
            decrypted[field] = value
    
    return decrypted
