"""Transcript encryption for secure storage at rest.

Provides optional encryption for transcript files using Fernet symmetric encryption.
Encryption is enabled when HIKAFLOW_ENCRYPTION_KEY is set.

Key management:
- Generate a key: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
- Set env: export HIKAFLOW_ENCRYPTION_KEY="your-key-here"
- Or store in ~/.hikaflow/credentials.json under "encryption_key"
"""

from __future__ import annotations

import base64
import json
import os
from pathlib import Path
from typing import Optional

# Try to import cryptography, but make it optional
try:
    from cryptography.fernet import Fernet, InvalidToken
    CRYPTOGRAPHY_AVAILABLE = True
except ImportError:
    CRYPTOGRAPHY_AVAILABLE = False
    Fernet = None  # type: ignore
    InvalidToken = Exception  # type: ignore


class EncryptionError(Exception):
    """Error during encryption/decryption."""
    pass


class TranscriptEncryption:
    """Handles encryption/decryption of transcript data."""

    def __init__(self, key: Optional[str] = None):
        """Initialize encryption with optional key.

        Args:
            key: Fernet key string. If None, tries to load from env/config.
        """
        self._key = key or self._load_key()
        self._fernet: Optional[Fernet] = None

        if self._key and CRYPTOGRAPHY_AVAILABLE:
            try:
                self._fernet = Fernet(self._key.encode() if isinstance(self._key, str) else self._key)
            except Exception as e:
                raise EncryptionError(f"Invalid encryption key: {e}") from e

    @property
    def enabled(self) -> bool:
        """Check if encryption is enabled and available."""
        return self._fernet is not None

    def _load_key(self) -> Optional[str]:
        """Load encryption key from environment or config file."""
        # Try environment variable first
        key = os.environ.get("HIKAFLOW_ENCRYPTION_KEY")
        if key:
            return key

        # Try credentials file
        credentials_path = Path.home() / ".hikaflow" / "credentials.json"
        if credentials_path.exists():
            try:
                with open(credentials_path) as f:
                    creds = json.load(f)
                    return creds.get("encryption_key")
            except (json.JSONDecodeError, IOError):
                pass

        return None

    def encrypt(self, data: bytes) -> bytes:
        """Encrypt data if encryption is enabled.

        Args:
            data: Raw bytes to encrypt.

        Returns:
            Encrypted bytes if enabled, original data if not.
        """
        if not self._fernet:
            return data

        try:
            return self._fernet.encrypt(data)
        except Exception as e:
            raise EncryptionError(f"Encryption failed: {e}") from e

    def decrypt(self, data: bytes) -> bytes:
        """Decrypt data if encryption is enabled.

        Args:
            data: Encrypted bytes to decrypt.

        Returns:
            Decrypted bytes if enabled, original data if not.
        """
        if not self._fernet:
            return data

        try:
            return self._fernet.decrypt(data)
        except InvalidToken:
            raise EncryptionError("Decryption failed: invalid key or corrupted data")
        except Exception as e:
            raise EncryptionError(f"Decryption failed: {e}") from e

    def encrypt_file(self, input_path: Path, output_path: Optional[Path] = None) -> Path:
        """Encrypt a file.

        Args:
            input_path: Path to file to encrypt.
            output_path: Path for encrypted file. Defaults to input_path + '.enc'

        Returns:
            Path to encrypted file.
        """
        if output_path is None:
            output_path = input_path.with_suffix(input_path.suffix + ".enc")

        with open(input_path, "rb") as f:
            data = f.read()

        encrypted = self.encrypt(data)

        with open(output_path, "wb") as f:
            f.write(encrypted)

        return output_path

    def decrypt_file(self, input_path: Path, output_path: Optional[Path] = None) -> Path:
        """Decrypt a file.

        Args:
            input_path: Path to encrypted file.
            output_path: Path for decrypted file. Defaults to removing '.enc' suffix.

        Returns:
            Path to decrypted file.
        """
        if output_path is None:
            if input_path.suffix == ".enc":
                output_path = input_path.with_suffix("")
            else:
                output_path = input_path.with_suffix(".dec")

        with open(input_path, "rb") as f:
            data = f.read()

        decrypted = self.decrypt(data)

        with open(output_path, "wb") as f:
            f.write(decrypted)

        return output_path


# Global instance for convenience
_encryption: Optional[TranscriptEncryption] = None


def get_encryption() -> TranscriptEncryption:
    """Get or create the global encryption instance."""
    global _encryption
    if _encryption is None:
        _encryption = TranscriptEncryption()
    return _encryption


def encrypt_transcript(data: bytes) -> bytes:
    """Encrypt transcript data using global encryption settings."""
    return get_encryption().encrypt(data)


def decrypt_transcript(data: bytes) -> bytes:
    """Decrypt transcript data using global encryption settings."""
    return get_encryption().decrypt(data)


def is_encryption_enabled() -> bool:
    """Check if encryption is enabled globally."""
    return get_encryption().enabled


def generate_key() -> str:
    """Generate a new Fernet encryption key.

    Returns:
        Base64-encoded key string suitable for HIKAFLOW_ENCRYPTION_KEY.
    """
    if not CRYPTOGRAPHY_AVAILABLE:
        raise EncryptionError("cryptography package not installed. Run: pip install cryptography")
    return Fernet.generate_key().decode()
