"""A tenant's time zone (app/core/timezones.py): the Super Admin sets it
(default Asia/Calcutta), every session's tenant carries it, and exports
print times in it."""

import uuid
from datetime import datetime, timezone

from sqlalchemy import text

from app.core.timezones import DEFAULT_TIMEZONE, check_timezone, localize, localize_rows, zone
from tests.conftest import AsyncSessionLocal
from tests.test_platform_admin import _platform_admin_token


async def test_super_admin_sets_a_tenants_time_zone(client):
    token, admin_id = await _platform_admin_token()
    headers = {"Authorization": f"Bearer {token}"}
    tenant_id = None
    try:
        resp = await client.post("/admin/tenants", headers=headers, json={"name": f"Pytest Tenant {uuid.uuid4().hex[:6]}"})
        assert resp.status_code == 201, resp.text
        tenant_id = resp.json()["id"]
        assert resp.json()["timezone"] == DEFAULT_TIMEZONE == "Asia/Calcutta"

        resp = await client.patch(f"/admin/tenants/{tenant_id}", headers=headers, json={"timezone": "Europe/London"})
        assert resp.status_code == 200, resp.text
        assert resp.json()["timezone"] == "Europe/London"

        # Unknown zones are refused; null leaves it as it was.
        resp = await client.patch(f"/admin/tenants/{tenant_id}", headers=headers, json={"timezone": "Mars/Olympus_Mons"})
        assert resp.status_code == 422
        resp = await client.patch(f"/admin/tenants/{tenant_id}", headers=headers, json={"timezone": None, "name": "Renamed"})
        assert resp.status_code == 200
        assert resp.json()["timezone"] == "Europe/London"

        listed = await client.get("/admin/tenants", headers=headers)
        assert next(t for t in listed.json() if t["id"] == tenant_id)["timezone"] == "Europe/London"

        # Every zone it can be set to, for the Settings dropdown — each one accepted.
        zones = (await client.get("/admin/timezones", headers=headers)).json()
        assert len(zones) > 400 and zones == sorted(zones)
        assert {"Asia/Calcutta", "Asia/Kolkata", "Europe/London", "America/New_York", "UTC"} <= set(zones)
        assert "Factory" not in zones
        assert all(check_timezone(z) == z for z in zones)
        assert (await client.get("/admin/timezones")).status_code == 401
    finally:
        async with AsyncSessionLocal() as db:
            async with db.begin():
                if tenant_id:
                    await db.execute(text("DELETE FROM roles WHERE tenant_id = :tid"), {"tid": tenant_id})
                    await db.execute(text("DELETE FROM tenants WHERE id = :tid"), {"tid": tenant_id})
                await db.execute(text("DELETE FROM platform_admins WHERE id = :aid"), {"aid": str(admin_id)})


async def test_a_signed_in_users_tenant_carries_its_time_zone(client, auth_headers):
    resp = await client.get("/tenants/me", headers=auth_headers)
    assert resp.status_code == 200
    assert check_timezone(resp.json()["timezone"])


def test_localize_converts_instants_only():
    india = zone("Asia/Calcutta")
    # A UTC timestamp, as a datetime or as the ISO text a JSON row holds.
    assert localize(datetime(2026, 10, 14, 9, 27, 1, 365095, tzinfo=timezone.utc), india) == datetime(2026, 10, 14, 14, 57, 1)
    assert localize("2026-10-14T09:27:01.365095+00:00", india) == datetime(2026, 10, 14, 14, 57, 1)
    assert localize("2026-10-14T21:00:00Z", india) == datetime(2026, 10, 15, 2, 30)
    # Dates, wall-clock times, naive datetimes and other text stay as they are.
    for unchanged in ("2026-10-22", "2026-10-22T10:30", "RTI/2026/000012", 42, None, datetime(2026, 10, 14, 9, 0)):
        assert localize(unchanged, india) == unchanged
    rows = localize_rows([{"created_at": "2026-10-14T09:27:01+00:00", "subject": "Re: timings"}], zone("Europe/London"))
    assert rows == [{"created_at": datetime(2026, 10, 14, 10, 27, 1), "subject": "Re: timings"}]


def test_unknown_zone_falls_back_to_the_default():
    assert str(zone("Not/AZone")) == DEFAULT_TIMEZONE
    assert str(zone(None)) == DEFAULT_TIMEZONE
