from datetime import datetime, timezone
from types import SimpleNamespace

import pytest

from tals import slice_objects


def obj(dt: datetime) -> SimpleNamespace:
    return SimpleNamespace(start=dt)


REF = datetime(2026, 3, 10)
REF_AWARE = datetime(2026, 3, 10, tzinfo=timezone.utc)


# --- Empty list ---


def test_empty_single_index():
    assert slice_objects([], "0", "start", REF) is None


def test_empty_negative_index():
    assert slice_objects([], "-1", "start", REF) is None


def test_empty_slice():
    assert slice_objects([], ":", "start", REF) == []


def test_empty_delta_slice():
    assert slice_objects([], "-7d:", "start", REF) == []


def test_empty_calendar_slice():
    assert slice_objects([], "0M:", "start", REF) == []


# --- Out of bounds ---


def test_oob_positive_index():
    assert slice_objects([obj(REF)], "5", "start", REF) is None


def test_oob_negative_index():
    assert slice_objects([obj(REF)], "-5", "start", REF) is None


# --- Time range with no matches ---


def test_delta_no_matches():
    a = obj(datetime(2025, 1, 1))
    result = slice_objects([a], "0M:", "start", REF)
    assert result == []


# --- Timezone errors ---


def test_ref_naive_object_aware():
    a = obj(datetime(2026, 3, 1, tzinfo=timezone.utc))
    with pytest.raises(TypeError, match="awareness mismatch"):
        slice_objects([a], ":", "start", REF)


def test_ref_aware_object_naive():
    a = obj(datetime(2026, 3, 1))
    with pytest.raises(TypeError, match="awareness mismatch"):
        slice_objects([a], ":", "start", REF_AWARE)


def test_mixed_awareness_in_objects():
    a = obj(datetime(2026, 3, 1, tzinfo=timezone.utc))
    b = obj(datetime(2026, 3, 2))  # naive
    with pytest.raises(TypeError, match="awareness mismatch"):
        slice_objects([a, b], ":", "start", REF_AWARE)


def test_different_aware_timezones_allowed():
    utc_plus2 = timezone(
        datetime(2026, 1, 1).utcoffset() or __import__("datetime").timedelta(hours=2)
    )
    # Use two different UTC offsets
    from datetime import timedelta, timezone as tz

    tz1 = tz(timedelta(hours=0))
    tz2 = tz(timedelta(hours=2))
    a = obj(datetime(2026, 3, 1, tzinfo=tz1))
    b = obj(datetime(2026, 3, 2, tzinfo=tz2))
    result = slice_objects([a, b], ":", "start", REF_AWARE)
    assert len(result) == 2


# --- Missing attribute ---


def test_missing_attribute():
    bad = SimpleNamespace(other=REF)
    with pytest.raises(AttributeError):
        slice_objects([bad], ":", "other_field", REF)


def test_wrong_timestamp_key():
    a = SimpleNamespace(start=datetime(2026, 3, 1))
    with pytest.raises(AttributeError):
        slice_objects([a], ":", "created_at", REF)
