# this should contain classes for how different object can be rendered, e.g. bold, italic, regular
from PIL import ImageFont
from enum import Enum
from typing import Tuple, Union, Optional
import os
import logging

# Set up logging for font loading
logger = logging.getLogger(__name__)


class FontWeight(Enum):
    NORMAL = "normal"
    BOLD = "bold"


class FontStyle(Enum):
    NORMAL = "normal"
    ITALIC = "italic"


class TextDecoration(Enum):
    NONE = "none"
    UNDERLINE = "underline"
    STRIKETHROUGH = "strikethrough"


class Font:
    """
    Font class to manage text rendering properties including font face, size, color, and styling.
    This class is used by the text renderer to determine how to render text.
    """

    def __init__(self, 
                 font_path: Optional[str] = None,
                 font_size: int = 16, 
                 colour: Tuple[int, int, int] = (0, 0, 0),
                 weight: FontWeight = FontWeight.NORMAL,
                 style: FontStyle = FontStyle.NORMAL,
                 decoration: TextDecoration = TextDecoration.NONE,
                 background: Optional[Tuple[int, int, int, int]] = None,
                 language = "en_EN",
                 min_hyphenation_width: Optional[int] = None):
        """
        Initialize a Font object with the specified properties.
        
        Args:
            font_path: Path to the font file (.ttf, .otf). If None, uses default font.
            font_size: Size of the font in points.
            colour: RGB color tuple for the text.
            weight: Font weight (normal or bold).
            style: Font style (normal or italic).
            decoration: Text decoration (none, underline, or strikethrough).
            background: RGBA background color for the text. If None, transparent background.
            language: Language code for hyphenation and text processing.
            min_hyphenation_width: Minimum width in pixels required for hyphenation to be considered.
                                 If None, defaults to 4 times the font size.
        """
        self._font_path = font_path
        self._font_size = font_size
        self._colour = colour
        self._weight = weight
        self._style = style
        self._decoration = decoration
        self._background = background if background else (255, 255, 255, 0)
        self.language = language
        self._min_hyphenation_width = min_hyphenation_width if min_hyphenation_width is not None else font_size * 4
        # Load the font file or use default
        self._load_font()
    
    def _get_bundled_font_path(self):
        """Get the path to the bundled font"""
        # Get the directory containing this module
        current_dir = os.path.dirname(os.path.abspath(__file__))
        # Navigate to the assets/fonts directory
        assets_dir = os.path.join(os.path.dirname(current_dir), 'assets', 'fonts')
        bundled_font_path = os.path.join(assets_dir, 'DejaVuSans.ttf')
        
        logger.debug(f"Font loading: current_dir = {current_dir}")
        logger.debug(f"Font loading: assets_dir = {assets_dir}")
        logger.debug(f"Font loading: bundled_font_path = {bundled_font_path}")
        logger.debug(f"Font loading: bundled font exists = {os.path.exists(bundled_font_path)}")
        
        if os.path.exists(bundled_font_path):
            logger.info(f"Found bundled font at: {bundled_font_path}")
            return bundled_font_path
        else:
            logger.warning(f"Bundled font not found at: {bundled_font_path}")
            return None
    
    def _load_font(self):
        """Load the font using PIL's ImageFont with consistent bundled font"""
        try:
            if self._font_path:
                # Use specified font path
                logger.info(f"Loading font from specified path: {self._font_path}")
                self._font = ImageFont.truetype(
                    self._font_path, 
                    self._font_size
                )
                logger.info(f"Successfully loaded font from: {self._font_path}")
            else:
                # Use bundled font for consistency across environments
                bundled_font_path = self._get_bundled_font_path()
                
                if bundled_font_path:
                    logger.info(f"Loading bundled font from: {bundled_font_path}")
                    self._font = ImageFont.truetype(bundled_font_path, self._font_size)
                    logger.info(f"Successfully loaded bundled font at size {self._font_size}")
                else:
                    # Only fall back to PIL's default font if bundled font is not available
                    logger.warning(f"Bundled font not available, falling back to PIL default font")
                    self._font = ImageFont.load_default()
                    
        except Exception as e:
            # Ultimate fallback to default font
            logger.error(f"Failed to load font: {e}, falling back to PIL default font")
            self._font = ImageFont.load_default()
    
    @property
    def font(self):
        """Get the PIL ImageFont object"""
        return self._font
    
    @property
    def font_size(self):
        """Get the font size"""
        return self._font_size
    
    @property
    def colour(self):
        """Get the text color"""
        return self._colour
    
    @property
    def color(self):
        """Alias for colour (American spelling)"""
        return self._colour
    
    @property
    def background(self):
        """Get the background color"""
        return self._background
    
    @property
    def weight(self):
        """Get the font weight"""
        return self._weight
    
    @property
    def style(self):
        """Get the font style"""
        return self._style
    
    @property
    def decoration(self):
        """Get the text decoration"""
        return self._decoration
    
    @property
    def min_hyphenation_width(self):
        """Get the minimum width required for hyphenation to be considered"""
        return self._min_hyphenation_width
    
    def with_size(self, size: int):
        """Create a new Font object with modified size"""
        return Font(
            self._font_path, 
            size, 
            self._colour,
            self._weight,
            self._style,
            self._decoration,
            self._background
        )
    
    def with_colour(self, colour: Tuple[int, int, int]):
        """Create a new Font object with modified colour"""
        return Font(
            self._font_path, 
            self._font_size, 
            colour,
            self._weight,
            self._style,
            self._decoration,
            self._background
        )
    
    def with_weight(self, weight: FontWeight):
        """Create a new Font object with modified weight"""
        return Font(
            self._font_path, 
            self._font_size, 
            self._colour,
            weight,
            self._style,
            self._decoration,
            self._background
        )
    
    def with_style(self, style: FontStyle):
        """Create a new Font object with modified style"""
        return Font(
            self._font_path, 
            self._font_size, 
            self._colour,
            self._weight,
            style,
            self._decoration,
            self._background
        )
    
    def with_decoration(self, decoration: TextDecoration):
        """Create a new Font object with modified decoration"""
        return Font(
            self._font_path, 
            self._font_size, 
            self._colour,
            self._weight,
            self._style,
            decoration,
            self._background
        )
