UI Services Architecture
========================

Consolidated service layer for ParameterFormManager operations.

The Problem: Monolithic Form Manager
-------------------------------------

The ParameterFormManager class originally contained all logic for parameter forms in a single 2600+ line class: widget finding, value collection, signal management, parameter operations, form initialization, and styling. This monolithic design made the code hard to test, extend, and maintain. Changes to one concern (e.g., widget styling) required understanding the entire class.

The Solution: Service-Oriented Architecture
---------------------------------------------

The UI services extract specialized responsibilities into focused service classes, each handling one concern. Services are grouped by related functionality (widget operations, value collection, signal management, parameter operations, form initialization) while maintaining clean interfaces. This enables testing individual services in isolation and makes the codebase easier to understand and extend.

Overview
--------

The UI services provide a clean separation of concerns for the ParameterFormManager.
Originally implemented as 17+ separate service files, these have been consolidated
into 5 cohesive services plus 2 base classes, reducing complexity while maintaining
all functionality.

Service Consolidation
---------------------

The services were restructured following the principle of grouping related functionality:

.. list-table:: Service Consolidation
   :header-rows: 1
   :widths: 30 40 30

   * - New Service
     - Merged From
     - Responsibility
   * - ``WidgetService``
     - WidgetFinder, WidgetStyling, WidgetUpdate
     - Widget finding, styling, and value updates
   * - ``ValueCollectionService``
     - NestedValueCollection, DataclassReconstruction, DataclassUnpacker
     - Value collection and dataclass operations
   * - ``SignalService``
     - SignalBlocking, SignalConnection, CrossWindowRegistration
     - Signal management and cross-window updates
   * - ``ParameterOpsService``
     - ParameterReset, PlaceholderRefresh
     - Parameter operations and placeholder management
   * - ``FormInitService``
     - InitializationServices, InitializationStepFactory, FormBuildOrchestrator, InitialRefreshStrategy
     - Form initialization and widget building

Standalone services kept as-is:

- ``EnabledFieldStylingService`` - Specific concern for enabled/disabled field styling
- ``FlagContextManager`` - Clean context manager for manager flags
- ``FieldChangeDispatcher`` - Unified event-driven field change handling (see :doc:`field_change_dispatcher`)
- ``ParameterServiceABC``, ``EnumDispatchService`` - Base classes for type-safe dispatch

WidgetService
-------------

Consolidated service for widget finding, styling, and value updates.

.. code-block:: python

    from pyqt_reactive.services.widget_service import WidgetService
    
    # Find widgets
    checkbox = WidgetService.find_optional_checkbox(manager, param_name)
    widget = WidgetService.get_widget_safe(manager, param_name)
    
    # Style widgets
    WidgetService.make_readonly(widget, color_scheme)
    WidgetService.apply_dimming(widget, opacity=0.5)
    
    # Update widget values (instance method)
    service = WidgetService()
    service.update_widget_value(widget, value, param_name, manager=manager)

Key methods:

- ``find_optional_checkbox(manager, param_name)`` - Find optional checkbox for a parameter
- ``find_nested_checkbox(manager, param_name)`` - Find checkbox in nested manager
- ``find_group_box(container, group_box_type)`` - Find group box within container
- ``get_widget_safe(manager, param_name)`` - Safely get widget from manager
- ``make_readonly(widget, color_scheme)`` - Make widget read-only without greying
- ``update_widget_value(widget, value, param_name, ...)`` - Update widget with signal blocking

ValueCollectionService
----------------------

Handles value collection from nested managers and dataclass operations.

It works hand-in-hand with ``ObjectState``:

- PFM uses ObjectState as the single source of truth for parameters and nested states.
- Live context collection walks ObjectStateRegistry (not PFMs) and uses ``get_user_modified_values``/overlays.
- Cancel/save flows rely on ObjectState baselines (mark_saved/restore_saved).

.. code-block:: python

    from pyqt_reactive.services.value_collection_service import ValueCollectionService

    service = ValueCollectionService()

    # Collect nested value with type-safe dispatch
    value = service.collect_nested_value(manager, param_name, nested_manager)

    # Unpack dataclass fields to instance attributes
    ValueCollectionService.unpack_to_self(target, source, prefix="config_")

Uses discriminated union dispatch based on ``ParameterInfo`` types:

- ``OptionalDataclassInfo`` - Optional[Dataclass] parameters
- ``DirectDataclassInfo`` - Direct dataclass parameters  
- ``GenericInfo`` - Generic/primitive parameters

SignalService
-------------

Manages Qt signal blocking, connection, and cross-window registration.

.. code-block:: python

    from pyqt_reactive.services.signal_service import SignalService
    
    # Block signals (context manager)
    with SignalService.block_signals(checkbox):
        checkbox.setChecked(True)
    
    # Block multiple widgets
    with SignalService.block_signals(widget1, widget2):
        widget1.setValue(1)
        widget2.setValue(2)
    
    # Connect all signals for a manager
    SignalService.connect_all_signals(manager)
    
    # Cross-window registration
    with SignalService.cross_window_registration(manager):
        dialog.exec()

ParameterOpsService
-------------------

Handles parameter reset and placeholder refresh operations.

.. code-block:: python

    from pyqt_reactive.services.parameter_ops_service import ParameterOpsService

    service = ParameterOpsService()

    # Reset parameter with type-safe dispatch
    service.reset_parameter(manager, param_name)

    # Refresh placeholders with live context from other windows
    service.refresh_with_live_context(manager)

    # Refresh all placeholders in a form
    service.refresh_all_placeholders(manager)

Uses discriminated union dispatch for reset operations:

- ``_reset_OptionalDataclassInfo`` - Reset Optional[Dataclass] with checkbox sync
- ``_reset_DirectDataclassInfo`` - Reset direct dataclass via nested manager
- ``_reset_GenericInfo`` - Reset generic field with context-aware value

FormInitService
---------------

Orchestrates form initialization with metaprogrammed services.

.. code-block:: python

    from pyqt_reactive.services.form_init_service import (
        FormBuildOrchestrator,
        InitialRefreshStrategy,
        ParameterExtractionService,
        ConfigBuilderService,
        ServiceFactoryService
    )

    # Extract parameters using metaprogrammed service
    extracted = ParameterExtractionService.build(object_instance, exclude_params, initial_values)

    # Build config using metaprogrammed service
    form_config = ConfigBuilderService.build(field_id, extracted, context_obj, color_scheme, parent_manager, service)

    # Create all services using metaprogrammed factory
    services = ServiceFactoryService.build()

    # Build widgets with unified async/sync path
    orchestrator = FormBuildOrchestrator()
    orchestrator.build_widgets(manager, content_layout, param_infos, use_async=True)

    # Execute initial refresh strategy
    InitialRefreshStrategy.execute(manager)

Key components:

- ``ParameterExtractionService`` - Extracts parameters from object instance
- ``ConfigBuilderService`` - Builds ParameterFormConfig with derived values
- ``ServiceFactoryService`` - Auto-instantiates all manager services
- ``FormBuildOrchestrator`` - Handles async/sync widget creation
- ``InitialRefreshStrategy`` - Enum-driven initial placeholder refresh

Type-Safe Dispatch Pattern
--------------------------

Services use discriminated union dispatch via ``ParameterServiceABC``:

.. code-block:: python

    class ParameterOpsService(ParameterServiceABC):
        def _get_handler_prefix(self) -> str:
            return '_reset_'

        def _reset_OptionalDataclassInfo(self, info, manager) -> None:
            # Handle Optional[Dataclass] reset
            ...

        def _reset_DirectDataclassInfo(self, info, manager) -> None:
            # Handle direct Dataclass reset
            ...

        def _reset_GenericInfo(self, info, manager) -> None:
            # Handle generic field reset
            ...

This pattern eliminates if/elif type-checking smell with polymorphic dispatch
based on the concrete ``ParameterInfo`` type.

Architecture Benefits
---------------------

The consolidated architecture provides:

- **Reduced File Count**: 17 files → 9 files (including base classes)
- **Cohesive Grouping**: Related functionality in single services
- **Consistent Patterns**: All services use same ABC-based dispatch
- **Clear Responsibilities**: Each service has well-defined scope
- **Easier Discovery**: Developers find functionality in fewer places
- **Maintainability**: Changes localized to single service files

See Also
--------

- :doc:`field_change_dispatcher` - Unified event-driven field change handling
- :doc:`service-layer-architecture` - Framework-agnostic service layer patterns
- :doc:`parameter_form_service_architecture` - ParameterFormService architecture
- :doc:`parameter_form_lifecycle` - Form lifecycle management
