"""Structural typing protocols for DataFrame and Series objects.

These protocols allow log_dataframe() and log_series() to accept any
object that quacks like a pandas/polars DataFrame or Series — without
requiring either library as a dependency.
"""

from __future__ import annotations

from typing import Any, Protocol, Sequence, runtime_checkable


@runtime_checkable
class DataFrameLike(Protocol):
    """Structural protocol for DataFrame-like objects.

    Both pandas.DataFrame and polars.DataFrame satisfy this protocol.
    For serialization, the implementation tries to_parquet() first
    (pandas), then write_parquet() (polars).
    """

    @property
    def shape(self) -> tuple[int, int]: ...

    @property
    def columns(self) -> Sequence[str]: ...

    def head(self, n: int = 5) -> DataFrameLike: ...

    def to_dict(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ...


@runtime_checkable
class SeriesLike(Protocol):
    """Structural protocol for Series-like objects.

    Both pandas.Series and polars.Series satisfy this protocol.
    """

    @property
    def name(self) -> str | None: ...

    @property
    def shape(self) -> tuple[int]: ...

    def to_frame(self) -> DataFrameLike: ...
