"""
Helpers to convert DateTimes to sqlite types.

.. name table:

==============================  =======================  =======================================
Function Name                   Default Named Converter  Accepts
==============================  =======================  =======================================
:meth:`aware_as_zulu_string`    ``z``                    AwareDateTime, AwareTime if already UTC
:meth:`aware_as_keeptz_string`  ``keeptz``               AwareDateTime, AwareTime
:meth:`naive_as_string`         ``naive``                NaiveDateTime, NaiveTime, Date
:meth:`any_temporal_as_iso`     ``ANY_temporal``         Any of the above
==============================  =======================  =======================================
"""

from datetime import timedelta, timezone
from datetype import (
    NaiveDateTime,
    AwareDateTime,
    Date,
    NaiveTime,
    AwareTime,
)

from coolqlite._common import ToSqlTypeError, ToSqlValueError


def any_temporal_as_iso(
    temporal: NaiveDateTime | AwareDateTime | Date | NaiveTime | AwareTime, /
) -> str:
    # pyright no likey datetype stuff for some reason
    match temporal:
        case AwareDateTime() | NaiveDateTime():  # pyright: ignore[reportGeneralTypeIssues]
            return temporal.isoformat(sep=" ")
        case Date() | AwareTime() | NaiveTime():  # pyright: ignore[reportGeneralTypeIssues]
            return temporal.isoformat()
        case _:
            raise ToSqlTypeError(f"{type(temporal)} is not a temporal type")


def aware_as_zulu_string(temporal: AwareDateTime | AwareTime, /) -> str:
    """Serialize an :class:`datetype.AwareDateTime`
    by adjusting it to UTC, then serializing
    as an iso-format string with a ``Z`` at the end.
    """
    match temporal:
        case AwareDateTime():  # pyright: ignore[reportGeneralTypeIssues]
            return (
                temporal.astimezone(timezone.utc).replace(tzinfo=None).isoformat(" ")
                + "Z"
            )
        case AwareTime() if temporal.utcoffset() == timedelta():  # pyright: ignore[reportGeneralTypeIssues]
            return temporal.replace(tzinfo=None).isoformat() + "Z"
        case AwareTime():  # pyright: ignore[reportGeneralTypeIssues]
            raise ToSqlValueError(
                f"Aware times can't be converted to UTC cleanly: {temporal}"
            )
        case NaiveDateTime() | NaiveTime() | Date():  # pyright: ignore[reportGeneralTypeIssues]
            raise ToSqlTypeError(f"Expected aware temporal type, got naive: {temporal}")
        case _:
            raise ToSqlTypeError(f"{type(temporal)} is not a temporal type")


# TODO: fix docs


def aware_as_keeptz_string(temporal: AwareDateTime | AwareTime, /) -> str:
    """Serialize an :class:`datetype.AwareDateTime`
    as an iso-format string.
    """
    match temporal:
        case AwareDateTime():  # pyright: ignore[reportGeneralTypeIssues]
            return temporal.isoformat(" ")
        case AwareTime():  # pyright: ignore[reportGeneralTypeIssues]
            return temporal.isoformat()
        case NaiveDateTime() | NaiveTime() | Date():  # pyright: ignore[reportGeneralTypeIssues]
            raise ToSqlTypeError(f"Expected aware temporal type, got naive: {temporal}")
        case _:
            raise ToSqlTypeError(f"{type(temporal)} is not a temporal type")


def naive_as_string(temporal: NaiveDateTime | NaiveTime | Date, /) -> str:
    """Serialize a :class:`datetype.NaiveDateTime`
    as an iso-format string.
    """
    match temporal:
        case Date() | NaiveTime():  # pyright: ignore[reportGeneralTypeIssues]
            return temporal.isoformat()
        case NaiveDateTime():  # pyright: ignore[reportGeneralTypeIssues]
            return temporal.isoformat(" ")
        case AwareDateTime() | AwareTime():  # pyright: ignore[reportGeneralTypeIssues]
            raise ToSqlTypeError(f"Expected naive temporal type, got aware: {temporal}")
        case _:
            raise ToSqlTypeError(f"{type(temporal)} is not a temporal type")
