from datetime import datetime
from typing import Callable, cast

from ...core.common import tzdatetime, Literal


'''
Depending on the specific data provider and your level of paranoia you might expect different behaviour.. E.g.:
- if your objects already have tz info, you might not need to call localize() at all
- it's safer when either all of your objects are tz aware or all are tz unware, not a mixture
- you might trust your original timezone, or it might just be UTC, and you want to use something more reasonable
'''
TzPolicy = Literal[
    'keep'   , # if datetime is tz aware, just preserve it
    'convert', # if datetime is tz aware, convert to provider's tz
    'throw'  , # if datetime is tz aware, throw exception
    # todo 'warn'? not sure if very useful
]

# backwards compatibility
Policy = TzPolicy

def default_policy() -> TzPolicy:
    try:
        from my.config import time as user_config
        return cast(TzPolicy, user_config.tz.policy)
    except Exception as e:
        # todo meh.. need to think how to do this more carefully
        # rationale: do not mess with user's data unless they want
        return 'keep'


def localize_with_policy(lfun: Callable[[datetime], tzdatetime], dt: datetime, policy: TzPolicy=default_policy()) -> tzdatetime:
    tz = dt.tzinfo
    if tz is None:
        return lfun(dt)

    if   policy == 'keep':
        return dt
    elif policy == 'convert':
        ldt = lfun(dt.replace(tzinfo=None))
        return dt.astimezone(ldt.tzinfo)
    else: # policy == 'error':
        raise RuntimeError(f"{dt} already has timezone information (use 'policy' argument to adjust this behaviour)")
