"""
Temporal workflows for polling operations in the Julee polling contrib module.

This module contains workflows that orchestrate polling operations with
Temporal's durability guarantees, providing retry logic, state management,
and reliable execution for endpoint polling and change detection.
"""

import logging
from abc import abstractmethod
from typing import Any

from temporalio import workflow

from julee.contrib.polling.domain.models.polling_config import PollingConfig
from julee.contrib.polling.domain.services.new_data_analyzer import NewDataAnalyzer
from julee.contrib.polling.domain.services.polling_result_handler import (
    PollingResultHandler,
)
from julee.contrib.polling.infrastructure.temporal.proxies import (
    WorkflowPollerServiceProxy,
)
from julee.contrib.polling.use_cases.poll_data import (
    PollDataRequest,
    PollDataUseCase,
)

logger = logging.getLogger(__name__)


@workflow.defn
class NewDataDetectionPipeline:
    """
    Temporal workflow for endpoint polling with new data detection.

    This workflow:
    1. Polls an endpoint using the configured polling service
    2. Compares result with previous completion to detect changes
    3. Runs the analyzer to identify new item IDs (if provided)
    4. Hands off to result handler when new data is detected
    5. Returns completion result for next scheduled execution

    The workflow uses Temporal's schedule last completion result feature
    to automatically receive the previous execution's result for comparison.

    Subclasses must implement get_handler() and get_analyzer() to supply the
    appropriate objects for each polling use case (credential, product, etc.).
    """

    def __init__(self) -> None:
        self.current_step = "initialized"
        self.endpoint_id: str | None = None
        self.has_new_data: bool = False

    @abstractmethod
    def get_handler(self) -> PollingResultHandler:
        """Return the PollingResultHandler for this pipeline."""
        ...

    @abstractmethod
    def get_analyzer(self) -> NewDataAnalyzer:
        """Return the NewDataAnalyzer for this pipeline."""
        ...

    @workflow.query
    def get_current_step(self) -> str:
        """Query method to get the current workflow step."""
        return self.current_step

    @workflow.query
    def get_endpoint_id(self) -> str | None:
        """Query method to get the endpoint ID being polled."""
        return self.endpoint_id

    @workflow.query
    def get_has_new_data(self) -> bool:
        """Query method to check if new data was detected."""
        return self.has_new_data

    @workflow.run
    async def run(
        self,
        config: PollingConfig | dict[str, Any],
    ) -> dict[str, Any]:
        """
        Execute the new data detection workflow.

        Args:
            config: Configuration for the polling operation (PollingConfig or dict
                    from Temporal schedule serialisation)

        Returns:
            Completion result containing polling result and detection metadata

        Raises:
            RuntimeError: If polling fails after retries
        """
        # Convert dict to PollingConfig if needed (Temporal schedules serialise args as dicts)
        if isinstance(config, dict):
            config = PollingConfig.model_validate(config)

        self.endpoint_id = config.endpoint_identifier

        previous_completion = workflow.get_last_completion_result()

        workflow.logger.info(
            "Starting new data detection pipeline",
            extra={
                "endpoint_id": self.endpoint_id,
                "polling_protocol": config.polling_protocol.value,
                "has_previous_completion": previous_completion is not None,
                "workflow_id": workflow.info().workflow_id,
                "run_id": workflow.info().run_id,
            },
        )

        self.current_step = "polling_endpoint"

        try:
            request = PollDataRequest(
                config=config,
                previous_completion=previous_completion,
            )
            use_case = PollDataUseCase(
                poller=WorkflowPollerServiceProxy(),
                handler=self.get_handler(),
                analyzer=self.get_analyzer(),
            )
            response = await use_case.execute(request)

            self.endpoint_id = response.endpoint_id
            self.has_new_data = response.new_items_found
            self.current_step = "completed"

            workflow.logger.info(
                "New data detection pipeline completed successfully",
                extra={
                    "endpoint_id": self.endpoint_id,
                    "has_new_data": self.has_new_data,
                },
            )

            return {
                "polling_result": {
                    "content_hash": response.content_hash,
                    "content": response.content,
                    "polled_at": response.polled_at,
                },
                "detection_result": {
                    "has_new_data": response.new_items_found,
                    "current_hash": response.content_hash,
                },
                "endpoint_id": response.endpoint_id,
                "completed_at": workflow.now().isoformat(),
            }

        except Exception as e:
            self.current_step = "failed"

            workflow.logger.error(
                "New data detection pipeline failed",
                extra={
                    "endpoint_id": self.endpoint_id,
                    "error": str(e),
                    "error_type": type(e).__name__,
                    "current_step": self.current_step,
                },
                exc_info=True,
            )

            raise
