"""
COM callback handlers for WebView2 events.

This module contains the COM object implementations that handle
callbacks from the WebView2 runtime.

All handlers follow a common pattern:
1. Check for errors in the callback arguments
2. Delegate to the WebView instance method
3. Handle internal signals (_InternalCancelSignal, _InternalExitSignal)
4. Convert unexpected exceptions to _InternalExitSignal
"""

from typing import TYPE_CHECKING, Any, Callable

import comtypes

from .._internal.logging import debug_log
from ..exceptions import _InternalCancelSignal, _InternalExitSignal
from .interfaces import (
    ICoreWebView2CreateCoreWebView2ControllerCompletedHandler,
    ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler,
    ICoreWebView2ProcessFailedEventHandler,
    ICoreWebView2WebMessageReceivedEventHandler,
)

if TYPE_CHECKING:
    from .core import WebView

_MODULE = "handlers"


def _safe_invoke(
    handler_name: str, callback: Callable[[], None], error_prefix: str
) -> int:
    """
    Safely invoke a callback with standardized exception handling.

    This helper function provides consistent exception handling for all
    COM callback handlers, reducing code duplication.

    Args:
        handler_name: Name of the handler for logging purposes.
        callback: The callback function to invoke.
        error_prefix: Prefix for error messages.

    Returns:
        0 (S_OK) on success.

    Raises:
        _InternalCancelSignal: If the callback raises this signal.
        _InternalExitSignal: If the callback fails or raises other exceptions.
    """
    try:
        callback()
    except _InternalExitSignal:
        raise
    except _InternalCancelSignal:
        raise
    except Exception as e:
        debug_log(f"{handler_name} failed: {e!r}", _MODULE)
        raise _InternalExitSignal(f"{error_prefix}: {e}")
    return 0


class EnvironmentCompletedHandler(comtypes.COMObject):
    """
    Handler for WebView2 environment creation completion.

    This handler is invoked when CreateCoreWebView2EnvironmentWithOptions
    completes, either successfully or with an error.
    """

    _com_interfaces_ = [ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler]

    def __init__(self, webview: "WebView"):
        self.webview = webview
        super().__init__()

    def Invoke(self, errorCode: int, createdEnvironment: Any) -> int:
        if errorCode != 0 or not createdEnvironment:
            debug_log(f"EnvironmentCompletedHandler error: {errorCode}", _MODULE)
            raise _InternalExitSignal(f"Environment creation failed: {errorCode}")
        return _safe_invoke(
            "EnvironmentCompletedHandler",
            lambda: self.webview._on_env_created(createdEnvironment),
            "Environment handler error",
        )


class ControllerCompletedHandler(comtypes.COMObject):
    """
    Handler for WebView2 controller creation completion.

    This handler is invoked when CreateCoreWebView2Controller completes,
    providing the controller that manages the WebView's window relationship.
    """

    _com_interfaces_ = [ICoreWebView2CreateCoreWebView2ControllerCompletedHandler]

    def __init__(self, webview: "WebView"):
        self.webview = webview
        super().__init__()

    def Invoke(self, errorCode: int, createdController: Any) -> int:
        if errorCode != 0 or not createdController:
            debug_log(f"ControllerCompletedHandler error: {errorCode}", _MODULE)
            raise _InternalExitSignal(f"Controller creation failed: {errorCode}")
        return _safe_invoke(
            "ControllerCompletedHandler",
            lambda: self.webview._on_controller_created(createdController),
            "Controller handler error",
        )


class WebMessageReceivedHandler(comtypes.COMObject):
    """
    Handler for web messages received from the frontend.

    This handler processes messages sent from JavaScript via
    window.chrome.webview.postMessage().
    """

    _com_interfaces_ = [ICoreWebView2WebMessageReceivedEventHandler]

    def __init__(self, webview: "WebView"):
        self.webview = webview
        super().__init__()

    def Invoke(self, sender: Any, args: Any) -> int:
        return _safe_invoke(
            "WebMessageReceivedHandler",
            lambda: self.webview._on_web_message(args),
            "Web message handler error",
        )


class ProcessFailedHandler(comtypes.COMObject):
    """
    Handler for WebView2 process failure events.

    This handler is invoked when the WebView2 browser process crashes
    or becomes unresponsive. This is a critical error that requires
    terminating the form.
    """

    _com_interfaces_ = [ICoreWebView2ProcessFailedEventHandler]

    def __init__(self, webview: "WebView"):
        self.webview = webview
        super().__init__()

    def Invoke(self, sender: Any, args: Any) -> int:
        debug_log("ProcessFailed event triggered", _MODULE)
        raise _InternalExitSignal("WebView2 process failed")
