"""
Company: eXonware.com
Author: Eng. Muhammad AlShehri
Email: connect@exonware.com
Version: 0.0.1.388
Generation Date: November 2, 2025

YAML serialization - Human-readable data serialization format.

Following I→A→XW pattern:
- I: ISerialization (interface)
- A: ASerialization (abstract base)
- XW: XWYamlSerializer (concrete implementation)
"""

from typing import Any, Optional, Union
from pathlib import Path

from ...base import ASerialization
from ....contracts import EncodeOptions, DecodeOptions
from ....defs import CodecCapability
from ....errors import SerializationError

# Lazy import for yaml (PyYAML)
try:
    import yaml
except ImportError:
    yaml = None


class XWYamlSerializer(ASerialization):
    """
    YAML serializer - follows I→A→XW pattern.
    
    I: ISerialization (interface)
    A: ASerialization (abstract base)
    XW: XWYamlSerializer (concrete implementation)
    
    Uses PyYAML library for YAML handling.
    
    Examples:
        >>> serializer = XWYamlSerializer()
        >>> 
        >>> # Encode data
        >>> yaml_str = serializer.encode({"key": "value"})
        >>> 
        >>> # Decode data
        >>> data = serializer.decode("key: value")
        >>> 
        >>> # Save to file
        >>> serializer.save_file({"database": {"host": "localhost"}}, "config.yaml")
        >>> 
        >>> # Load from file
        >>> config = serializer.load_file("config.yaml")
    """
    
    def __init__(self):
        """Initialize YAML serializer."""
        super().__init__()
        if yaml is None:
            raise ImportError(
                "PyYAML is required for YAML serialization. "
                "Install with: pip install PyYAML"
            )
    
    # ========================================================================
    # CODEC METADATA
    # ========================================================================
    
    @property
    def codec_id(self) -> str:
        return "yaml"
    
    @property
    def media_types(self) -> list[str]:
        return ["application/x-yaml", "text/yaml", "text/x-yaml"]
    
    @property
    def file_extensions(self) -> list[str]:
        return [".yaml", ".yml", ".clang-format", ".travis.yml", ".gitlab-ci.yml"]
    
    @property
    def format_name(self) -> str:
        return "YAML"
    
    @property
    def mime_type(self) -> str:
        return "application/x-yaml"
    
    @property
    def is_binary_format(self) -> bool:
        return False  # YAML is text-based
    
    @property
    def supports_streaming(self) -> bool:
        return True  # YAML supports multiple documents
    
    @property
    def capabilities(self) -> CodecCapability:
        return CodecCapability.BIDIRECTIONAL
    
    @property
    def aliases(self) -> list[str]:
        return ["yaml", "YAML", "yml", "YML"]
    
    # ========================================================================
    # CORE ENCODE/DECODE (Using PyYAML library)
    # ========================================================================
    
    def encode(self, value: Any, *, options: Optional[EncodeOptions] = None) -> Union[bytes, str]:
        """
        Encode data to YAML string.
        
        Uses PyYAML's yaml.dump().
        
        Args:
            value: Data to serialize
            options: YAML options (default_flow_style, sort_keys, etc.)
        
        Returns:
            YAML string
        
        Raises:
            SerializationError: If encoding fails
        """
        try:
            opts = options or {}
            
            # Common YAML options
            default_flow_style = opts.get('default_flow_style', False)
            sort_keys = opts.get('sort_keys', False)
            indent = opts.get('indent', 2)
            
            # Encode to YAML string
            yaml_str = yaml.dump(
                value,
                default_flow_style=default_flow_style,
                sort_keys=sort_keys,
                indent=indent,
                allow_unicode=opts.get('allow_unicode', True),
                Dumper=opts.get('Dumper', yaml.SafeDumper)
            )
            
            return yaml_str
            
        except (yaml.YAMLError, TypeError) as e:
            raise SerializationError(
                f"Failed to encode YAML: {e}",
                format_name=self.format_name,
                original_error=e
            )
    
    def decode(self, repr: Union[bytes, str], *, options: Optional[DecodeOptions] = None) -> Any:
        """
        Decode YAML string to data.
        
        Uses PyYAML's yaml.safe_load() for security.
        
        Args:
            repr: YAML string (bytes or str)
            options: YAML options (Loader, etc.)
        
        Returns:
            Decoded Python object
        
        Raises:
            SerializationError: If decoding fails
        """
        try:
            # Convert bytes to str if needed
            if isinstance(repr, bytes):
                repr = repr.decode('utf-8')
            
            opts = options or {}
            
            # Decode from YAML string (using safe_load for security)
            loader = opts.get('Loader', yaml.SafeLoader)
            data = yaml.load(repr, Loader=loader)
            
            return data
            
        except (yaml.YAMLError, UnicodeDecodeError) as e:
            raise SerializationError(
                f"Failed to decode YAML: {e}",
                format_name=self.format_name,
                original_error=e
            )


# Backward compatibility alias
YamlSerializer = XWYamlSerializer

