"""Definition of get_state function."""

from datetime import datetime, UTC
from pandera.typing import DataFrame
import pandas as pd
import pandera.pandas as pa
import sqlalchemy as sa

from utils.database.tables import (
    States,
    StatesMeta,
)
from utils.database.dataframes import SensorStateSchema
from utils.database import get_db_session


@pa.check_types
def get_state(
    entity_id: str,
    limit: int | None = None,
    start_time: datetime | None = None,
    end_time: datetime | None = None,
) -> DataFrame[SensorStateSchema]:
    """
    Retrieve sensor state data.

    Args:
        entity_id: The entity ID of the sensor.
        limit: Number of recent records to retrieve (default is None for all records).
        start_time: Start of time range (inclusive). If None, no lower bound.
        end_time: End of time range (inclusive). If None, no upper bound.

    Returns:
        DataFrame[SensorStateSchema]: The retrieved sensor state.
    """

    # Create a new database session
    session = get_db_session()

    # Prepare the base statement
    stmt = (
        sa.select(
            States.state,
            sa.func.to_timestamp(States.last_updated_ts).label("time"),
        )
        .join(
            StatesMeta,
            States.metadata_id == StatesMeta.metadata_id,
        )
        .where(StatesMeta.entity_id == entity_id)
    )

    # Add time range filters if provided
    if start_time is not None:
        start_ts = start_time.astimezone(UTC).timestamp()
        stmt = stmt.where(States.last_updated_ts >= start_ts)

    if end_time is not None:
        end_ts = end_time.astimezone(UTC).timestamp()
        stmt = stmt.where(States.last_updated_ts <= end_ts)

    # Order by time descending and apply limit if specified
    stmt = stmt.order_by(States.last_updated_ts.desc())

    if limit is not None:
        stmt = stmt.limit(limit)

    # Execute query
    with session.begin() as s:
        df = pd.read_sql(stmt, s.connection())

    # Handle empty results
    if len(df) == 0:
        # Create empty DataFrame with correct schema
        empty_df = pd.DataFrame(
            {
                "time": pd.Series([], dtype="datetime64[ns, UTC]"),
                "state": pd.Series([], dtype="object"),
            }
        )
        return DataFrame[SensorStateSchema](empty_df)

    # Reorder columns to match schema definition
    df = df[["time", "state"]]

    # Convert time column to nanosecond precision (PostgreSQL returns microseconds)
    df["time"] = df["time"].dt.as_unit("ns")

    return DataFrame[SensorStateSchema](df)
