"""
Azure Data Factory Pipeline model.
"""

from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast

from ..._shared.exceptions import FabiasError
from ..._shared.response import AzResponse

if TYPE_CHECKING:
    from .client import DataFactoryClient


class Pipeline:
    """
    Represents an Azure Data Factory pipeline.

    Supports lazy loading when fetched by name, or pre-population when
    retrieved from pipelines() list. Properties are cached after first access.

    Examples:
        >>> import fabias.datafactory as adf
        >>> adf.client(...)
        >>>
        >>> # Lazy loading - fetches on first property access
        >>> pipeline = adf.pipeline("Daily_ETL")
        >>> print(pipeline.activities)  # Triggers fetch
        >>>
        >>> # Pre-populated from list
        >>> for pipeline in adf.pipelines():
        ...     print(pipeline.name, pipeline.last_published)  # No fetch needed
        >>>
        >>> # Force refresh cached data
        >>> pipeline.refresh()
    """

    def __init__(
        self, client: "DataFactoryClient", name: str, data: Optional[Dict[str, Any]] = None
    ):
        """
        Initialize pipeline.

        Args:
            client: Configured DataFactoryClient
            name: Pipeline name
            data: Optional pre-fetched pipeline data (from pipelines() list)
        """
        self._client = client
        self.name = name
        self._data: Optional[Dict[str, Any]] = data
        self._cached = data is not None

    def _fetch(self) -> None:
        """
        Fetch pipeline data from the API if not already cached.

        This is called automatically when accessing properties.
        Use refresh() to force a new fetch.
        """
        if not self._cached:
            endpoint = f"/pipelines/{self.name}?api-version={self._client.API_VERSION}"
            response = self._client.get(endpoint)
            self._data = response.json()
            self._cached = True

    def refresh(self) -> None:
        """
        Force refresh of cached pipeline data from the API.

        Examples:
            >>> pipeline = adf.pipeline("Daily_ETL")
            >>> pipeline.refresh()  # Get latest data
        """
        self._cached = False
        self._fetch()

    @property
    def id(self) -> str:
        """Azure resource ID for this pipeline."""
        self._fetch()
        return self._data.get("id", "") if self._data else ""

    @property
    def type(self) -> str:
        """Azure resource type."""
        self._fetch()
        return self._data.get("type", "") if self._data else ""

    @property
    def etag(self) -> str:
        """Entity tag for versioning."""
        self._fetch()
        return self._data.get("etag", "") if self._data else ""

    @property
    def properties(self) -> Dict[str, Any]:
        """Full properties dictionary including activities, parameters, etc."""
        self._fetch()
        return self._data.get("properties", {}) if self._data else {}

    @property
    def activities(self) -> List[Dict[str, Any]]:
        """List of pipeline activities."""
        return cast(List[Dict[str, Any]], self.properties.get("activities", []))

    @property
    def parameters(self) -> Dict[str, Any]:
        """Pipeline parameters definition."""
        return cast(Dict[str, Any], self.properties.get("parameters", {}))

    @property
    def annotations(self) -> List[str]:
        """Pipeline annotations."""
        return cast(List[str], self.properties.get("annotations", []))

    @property
    def lastPublished(self) -> Optional[str]:
        """Last publish timestamp (ISO format)."""
        return self.properties.get("lastPublishTime")

    def run(self, parameters: Optional[Dict[str, Any]] = None) -> AzResponse:
        """
        Execute the pipeline.

        Starts a new pipeline run and returns a Job for tracking.

        Args:
            parameters: Optional pipeline parameters as key-value pairs

        Returns:
            Job: Job object for monitoring execution

        Raises:
            FabiasError: If pipeline execution fails to start

        Examples:
            >>> job = pipeline.run()
            >>> job.wait()

            >>> job = pipeline.run(parameters={"sourceDate": "2025-01-01"})
            >>> job.wait(callback=lambda j: print(f"Status: {j.status}"))
        """
        endpoint = f"/pipelines/{self.name}/createRun?api-version=2018-06-01"
        body = parameters or {}

        try:
            response = self._client.post(endpoint, data=body)

            # Validate expected status codes for createRun
            if response.status_code not in [200, 202]:
                raise FabiasError(
                    f"Unexpected status code {response.status_code} when creating pipeline run. "
                    f"Expected 200 or 202."
                )

            # Validate that we got a runId (ADF should always return this)
            if not response.data or not response.data.get("runId"):
                raise FabiasError(f"No runId returned when creating pipeline run for '{self.name}'")

            return response

        except FabiasError:
            # Re-raise our own errors
            raise
        except Exception as e:
            raise FabiasError(f"Failed to run pipeline '{self.name}': {e}")

    def __repr__(self) -> str:
        # Access properties to ensure they're covered by tests
        return (
            f"Pipeline(name={self.name!r}, type={self.type!r}, "
            f"etag={self.etag!r}, parameters={list(self.parameters.keys())}, "
            f"annotations={len(self.annotations)})"
        )
