"""
Toggle Line Layer Labels Action for Right-click Utilities and Shortcuts Hub

Toggles label visibility for line layers when a line feature is clicked.
"""

from .base_action import BaseAction
from ..i18n import tr
from qgis.core import QgsVectorLayer, QgsPalLayerSettings, QgsTextFormat


class ToggleLineLabelsAction(BaseAction):
    """Action to toggle label visibility for line layers."""
    
    def __init__(self):
        """Initialize the action with metadata and configuration."""
        super().__init__()
        
        # Required properties
        self.action_id = "toggle_line_labels"
        self.name = "Toggle Line Layer Labels"
        self.category = "Editing"
        self.description = "Toggle label visibility for the line layer of the selected line feature. Switches between showing and hiding layer labels."
        self.enabled = True
        
        # Action scoping configuration
        self.set_action_scope('layer')
        self.set_supported_scopes(['layer'])
        
        # Feature type support
        self.set_supported_click_types(['line', 'multiline'])
        self.set_supported_geometry_types(['line', 'multiline'])
    
    def get_settings_schema(self):
        """
        Define the settings schema for this action.
        
        Returns:
            dict: Settings schema with setting definitions
        """
        return {
            'label_field': {
                'type': 'str',
                'default': '',
                'label': 'Label Field',
                'description': 'Field to use for labeling. If empty, first text/string field will be used.',
            },
            'label_placement': {
                'type': 'choice',
                'default': 'line',
                'label': 'Label Placement',
                'description': 'Default label placement when toggling labels on',
                'options': ['line', 'above', 'below', 'map'],
            },
            'label_size': {
                'type': 'float',
                'default': 10.0,
                'label': 'Label Size',
                'description': 'Default label text size when toggling labels on',
                'min': 1.0,
                'max': 50.0,
                'step': 0.5,
            },
        }
    
    def _get_label_field(self, layer):
        """
        Determine the best field to use for labeling.
        
        Args:
            layer (QgsVectorLayer): The layer to find a label field for
        
        Returns:
            str: Name of the field to use for labeling, or empty string
        """
        # First, check if a specific label field is set in settings
        label_field = str(self.get_setting('label_field', '')).strip()
        if label_field and label_field in [field.name() for field in layer.fields()]:
            return label_field
        
        # Check for "id" field first (case-insensitive)
        for field in layer.fields():
            if field.name().lower() == 'id':
                return field.name()
        
        # If no "id" field, find the first text/string field
        for field in layer.fields():
            if field.type() in [2, 10]:  # QVariant::String types
                return field.name()
        
        return ''
    
    def execute(self, context):
        """
        Execute the toggle line labels action.
        
        Args:
            context (dict): Context dictionary with click information
        """
        # Extract context elements
        detected_features = context.get('detected_features', [])
        
        if not detected_features:
            self.show_error(tr("Error"), tr("No features found at this location"))
            return
        
        # Get the layer of the first detected feature
        layer = detected_features[0].layer
        
        # Verify it's a line layer
        if not isinstance(layer, QgsVectorLayer) or layer.geometryType() != 1:  # 1 is line geometry type
            self.show_error(tr("Error"), tr("This action works only with line layers"))
            return
        
        try:
            # Determine current label state
            labeling_manager = layer.labeling()
            is_labels_enabled = labeling_manager is not None and layer.labelsEnabled()
            
            # Toggle label visibility
            layer.setLabelsEnabled(not is_labels_enabled)
            
            # If enabling labels and no labeling is set up
            if not is_labels_enabled:
                # Get settings with type conversion
                label_placement = str(self.get_setting('label_placement', 'line'))
                label_size = float(self.get_setting('label_size', 10.0))
                
                # Find a suitable label field
                label_field = self._get_label_field(layer)
                
                if label_field:
                    # Create new labeling settings
                    pal_layer_settings = QgsPalLayerSettings()
                    pal_layer_settings.enabled = True
                    pal_layer_settings.fieldName = label_field
                    
                    # Configure text format
                    text_format = QgsTextFormat()
                    text_format.setSize(label_size)
                    pal_layer_settings.setFormat(text_format)
                    
                    # Set placement
                    placement_map = {
                        'line': QgsPalLayerSettings.Line,
                        'above': QgsPalLayerSettings.Line,
                        'below': QgsPalLayerSettings.Line,
                        'map': QgsPalLayerSettings.Line
                    }
                    pal_layer_settings.placement = placement_map.get(label_placement, QgsPalLayerSettings.Line)
                    
                    # Additional configuration for 'above' and 'below' placements
                    if label_placement == 'above':
                        pal_layer_settings.placementFlags = QgsPalLayerSettings.PlaceAboveLine
                    elif label_placement == 'below':
                        pal_layer_settings.placementFlags = QgsPalLayerSettings.PlaceBelowLine
                    
                    # Apply labeling settings
                    from qgis.core import QgsVectorLayerSimpleLabeling
                    layer.setLabeling(QgsVectorLayerSimpleLabeling(pal_layer_settings))
                    layer.setLabelsEnabled(True)
                else:
                    # No suitable label field found
                    self.show_warning(tr("No Label Field"), 
                        tr("Could not find a suitable field for labeling. Please set a label field in the action settings or add a text field to the layer."))
            
            # Refresh the layer to show changes
            layer.triggerRepaint()
            
            # Show feedback
            status = tr("enabled") if not is_labels_enabled else tr("disabled")
            self.show_info(tr("Label Visibility"), tr("Labels for layer '{layer}' have been {status}.").format(layer=layer.name(), status=status))

            # Record informational history entry (not undoable)
            try:
                new_enabled = not is_labels_enabled
                labeling_info = None
                try:
                    labeling_mgr = layer.labeling() if hasattr(layer, 'labeling') else None
                    if labeling_mgr is not None and layer.labelsEnabled():
                        try:
                            settings = labeling_mgr.settings()
                        except Exception:
                            settings = None

                        if settings is not None:
                            try:
                                field_name = getattr(settings, 'fieldName', None)
                                is_expr = getattr(settings, 'isExpression', False)
                                placement = getattr(settings, 'placement', None)
                            except Exception:
                                field_name = None
                                is_expr = False
                                placement = None

                            size = None
                            try:
                                fmt = getattr(settings, 'format', None)
                                if fmt is not None:
                                    if callable(getattr(fmt, 'size', None)):
                                        size = fmt.size()
                                    elif hasattr(fmt, 'size'):
                                        size = fmt.size
                            except Exception:
                                size = None

                            labeling_info = {
                                'enabled': bool(new_enabled),
                                'fieldName': field_name,
                                'isExpression': bool(is_expr),
                                'placement': placement,
                                'size': size
                            }
                except Exception:
                    labeling_info = None

                # Create a lightweight layer descriptor and record informational entry
                try:
                    layer_desc = self.create_layer_descriptor(layer)
                except Exception:
                    layer_desc = {'layer_name': layer.name()}

                self.record_informational(
                    description=f"Labels for layer '{layer.name()}' {status}.",
                    meta={'layer': layer_desc, 'labeling': labeling_info}
                )
            except Exception:
                pass
        
        except Exception as e:
            self.show_error(tr("Error"), tr("Failed to toggle labels: {error}").format(error=str(e)))


# Create global instance for automatic discovery
toggle_line_labels_action = ToggleLineLabelsAction()
