"""
Result-Wrapper für Query-Ergebnisse mit optionaler DataFrame-Konvertierung.

Diese Wrapper-Klassen ermöglichen transparente Nutzung von Query-Ergebnissen
als Listen/Dictionaries mit optionaler .to_df() Konvertierung.
"""

from __future__ import annotations

from collections.abc import Iterator, Sequence
from typing import TYPE_CHECKING, Generic, TypeVar, overload

if TYPE_CHECKING:
    import pandas as pd

    from .highlevel_client import QuestraData

# Optionale pandas Integration
try:
    import pandas as pd

    _PANDAS_AVAILABLE = True
except ImportError:
    _PANDAS_AVAILABLE = False


T = TypeVar("T")


class QueryResult(Sequence[T], Generic[T]):
    """
    Wrapper für Query-Ergebnisse mit optionaler DataFrame-Konvertierung.

    Verhält sich transparent wie eine Liste, bietet aber zusätzlich
    die Methode `to_df()` für pandas DataFrame-Konvertierung (nur bei dict-Daten).

    Args:
        data: Liste von Objekten (Query-Ergebnisse)

    Examples:
        ```python
        # Direkte Nutzung wie Liste (mit Dictionaries)
        items = client.list_items("Devices")
        for item in items:
            print(item["Name"])

        first_device = items[0]
        device_count = len(items)

        # Optional: DataFrame-Konvertierung (nur bei dict-Daten)
        df = items.to_df()

        # Nutzung mit Model-Objekten
        namespaces = client.list_namespaces()
        for ns in namespaces:
            print(ns.name)
        ```
    """

    def __init__(self, data: list[T]):
        self._data = data

    def to_df(self) -> pd.DataFrame:
        """
        Konvertiert die Ergebnisse zu einem pandas DataFrame.

        Funktioniert nur, wenn die Daten Dictionaries sind.
        Bei Model-Objekten werden diese automatisch zu Dicts konvertiert (via model_dump()).

        Returns:
            pandas DataFrame mit den Query-Ergebnissen

        Raises:
            ImportError: Wenn pandas nicht installiert ist
        """
        if not _PANDAS_AVAILABLE:
            raise ImportError(
                "pandas ist nicht installiert. Installiere es mit: pip install pandas"
            )

        # Wenn Daten bereits Dicts sind, direkt nutzen
        if self._data and isinstance(self._data[0], dict):
            return pd.DataFrame(self._data)

        # Bei Model-Objekten: konvertiere zu Dicts
        # Nutze model_dump() falls verfügbar (Pydantic), sonst __dict__
        data_dicts = []
        for item in self._data:
            if hasattr(item, "model_dump"):
                data_dicts.append(item.model_dump())  # type: ignore
            elif hasattr(item, "__dict__"):
                data_dicts.append(vars(item))
            else:
                # Fallback für primitive Typen
                data_dicts.append({"value": item})

        return pd.DataFrame(data_dicts)

    def __iter__(self) -> Iterator[T]:
        return iter(self._data)

    def __len__(self) -> int:
        return len(self._data)

    @overload
    def __getitem__(self, index: int) -> T: ...

    @overload
    def __getitem__(self, index: slice) -> list[T]: ...

    def __getitem__(self, index: int | slice) -> T | list[T]:
        return self._data[index]

    def __repr__(self) -> str:
        return f"QueryResult({self._data!r})"

    def __str__(self) -> str:
        return str(self._data)

    def __eq__(self, other: object) -> bool:
        """Vergleicht QueryResult mit anderen Sequenzen oder QueryResults."""
        if isinstance(other, QueryResult):
            return self._data == other._data
        if isinstance(other, list):
            return self._data == other
        return NotImplemented


class TimeSeriesResult(dict[str, dict]):
    """
    Wrapper für TimeSeries-Query-Ergebnisse mit DataFrame-Konvertierung.

    Verhält sich wie ein normales Dictionary, bietet aber zusätzlich
    die Methode `to_df()` für pandas DataFrame-Konvertierung.

    Args:
        data: Dictionary mit Item-ID als Key und TimeSeries-Daten als Value
        client: Referenz zum QuestraData-Client für DataFrame-Konvertierung

    Examples:
        ```python
        # Direkte Nutzung wie Dictionary
        result = client.list_timeseries_values(...)
        for item_id, data in result.items():
            print(f"Item {item_id}: {len(data['timeseries'])} properties")

        # Optional: DataFrame-Konvertierung
        df = result.to_df()
        df = result.to_df(properties=["stromzaehlernummer"])
        ```
    """

    def __init__(self, data: dict[str, dict], client: QuestraData):
        super().__init__(data)
        self._client = client

    def to_df(
        self, include_metadata: bool = True, properties: list[str] | None = None
    ) -> pd.DataFrame:
        """
        Konvertiert die TimeSeries-Ergebnisse zu einem pandas DataFrame.

        Args:
            include_metadata: Item-Metadaten als Spalten einbeziehen (wird ignoriert im Pivot-Format)
            properties: Liste normaler Properties die als Spalten-Ebenen hinzugefügt werden

        Returns:
            pandas DataFrame im Pivot-Format mit time als Index

        Raises:
            ImportError: Wenn pandas nicht installiert ist

        Examples:
            ```python
            result = client.list_timeseries_values(...)

            # Einfacher DataFrame
            df = result.to_df()

            # Mit zusätzlichen Properties als Spalten
            df = result.to_df(properties=["stromzaehlernummer", "standort"])
            ```
        """
        return self._client._convert_timeseries_to_dataframe(
            dict(self), include_metadata=include_metadata, properties=properties
        )
