# -*- coding: utf-8 -*-
"""Detect the system IANA timezone.

Kept in its own module to avoid circular imports between config.py and
utils.py.  Uses only the standard library; always returns a valid string
(falls back to ``"UTC"``).
"""

from __future__ import annotations

import os
from datetime import datetime, timezone
from typing import Optional


def _is_iana(name: Optional[str]) -> bool:
    """Return True if *name* looks like an IANA tz id."""
    return bool(name and "/" in name)


def detect_system_timezone() -> str:
    """Return the IANA timezone name of the host.

    Falls back to ``"UTC"`` when detection fails.  This function
    must *never* raise — any unexpected error is swallowed.
    """
    try:
        return _detect_system_timezone_inner()
    except Exception:
        return "UTC"


def _detect_system_timezone_inner() -> str:  # noqa: R0911
    probes = [_probe_python, _probe_env]
    if os.name == "nt":
        probes.append(_probe_windows_registry)
    else:
        probes += [
            _probe_etc_timezone,
            _probe_localtime_link,
            _probe_sysconfig_clock,
            _probe_timedatectl,
        ]
    for probe in probes:
        result = probe()
        if result is not None:
            return result
    return "UTC"


def _probe_python() -> Optional[str]:
    """Ask the Python runtime for the local IANA name."""
    try:
        name = (
            datetime.now(timezone.utc)
            .astimezone()
            .tzinfo.tzname(None)  # type: ignore[union-attr]
        )
        if _is_iana(name):
            return name
    except Exception:
        pass
    return None


def _probe_env() -> Optional[str]:
    """Check the ``$TZ`` environment variable."""
    tz = os.environ.get("TZ", "")
    return tz if _is_iana(tz) else None


_WIN_TO_IANA = {
    "China Standard Time": "Asia/Shanghai",
    "Taipei Standard Time": "Asia/Taipei",
    "Tokyo Standard Time": "Asia/Tokyo",
    "Korea Standard Time": "Asia/Seoul",
    "Singapore Standard Time": "Asia/Singapore",
    "India Standard Time": "Asia/Kolkata",
    "Arabian Standard Time": "Asia/Dubai",
    "Russian Standard Time": "Europe/Moscow",
    "W. Europe Standard Time": "Europe/Berlin",
    "Romance Standard Time": "Europe/Paris",
    "GMT Standard Time": "Europe/London",
    "Eastern Standard Time": "America/New_York",
    "Central Standard Time": "America/Chicago",
    "Mountain Standard Time": "America/Denver",
    "Pacific Standard Time": "America/Los_Angeles",
    "US Mountain Standard Time": "America/Phoenix",
    "Atlantic Standard Time": "America/Halifax",
    "Hawaiian Standard Time": "Pacific/Honolulu",
    "AUS Eastern Standard Time": "Australia/Sydney",
    "New Zealand Standard Time": "Pacific/Auckland",
    "Cen. Australia Standard Time": "Australia/Adelaide",
    "E. Africa Standard Time": "Africa/Nairobi",
    "SE Asia Standard Time": "Asia/Bangkok",
    "West Pacific Standard Time": "Pacific/Port_Moresby",
    "SA Eastern Standard Time": "America/Sao_Paulo",
    "UTC": "UTC",
}


def _probe_windows_registry() -> Optional[str]:
    """Read the current timezone from the Windows registry."""
    try:
        import winreg

        reg_path = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path)
        try:
            win_tz = winreg.QueryValueEx(key, "TimeZoneKeyName")[0]
        finally:
            winreg.CloseKey(key)
        return _WIN_TO_IANA.get(win_tz)
    except Exception:
        pass
    return None


def _probe_etc_timezone() -> Optional[str]:
    """Read ``/etc/timezone`` (Debian / Ubuntu)."""
    try:
        with open("/etc/timezone", encoding="utf-8") as fh:
            name = fh.read().strip()
            if _is_iana(name):
                return name
    except (OSError, ValueError):
        pass
    return None


def _probe_localtime_link() -> Optional[str]:
    """Resolve the ``/etc/localtime`` symlink."""
    try:
        link = os.readlink("/etc/localtime")
        if "zoneinfo/" in link:
            return link.split("zoneinfo/", 1)[1]
    except OSError:
        pass
    return None


def _probe_sysconfig_clock() -> Optional[str]:
    """Parse ``/etc/sysconfig/clock`` (CentOS / RHEL ≤ 6)."""
    try:
        with open("/etc/sysconfig/clock", encoding="utf-8") as fh:
            for raw in fh:
                if raw.strip().startswith("ZONE="):
                    zone = raw.split("=", 1)[1].strip().strip('"').strip("'")
                    if _is_iana(zone):
                        return zone
    except (OSError, ValueError):
        pass
    return None


def _probe_timedatectl() -> Optional[str]:
    """Query ``timedatectl`` (systemd)."""
    import subprocess  # delayed: avoid cost on happy path

    # systemd ≥ 239 — machine-readable output
    try:
        out = subprocess.check_output(
            [
                "timedatectl",
                "show",
                "-p",
                "Timezone",
                "--value",
            ],
            text=True,
            timeout=1,
            stderr=subprocess.DEVNULL,
        ).strip()
        if _is_iana(out):
            return out
    except Exception:
        pass

    # systemd < 239 (e.g. CentOS 7) — parse human output
    try:
        out = subprocess.check_output(
            ["timedatectl", "status"],
            text=True,
            timeout=1,
            stderr=subprocess.DEVNULL,
        )
        for line in out.splitlines():
            if "time zone" in line.lower():
                # "Time zone: Asia/Shanghai (CST, +0800)"
                part = line.split(":", 1)[1]
                part = part.strip().split()[0]
                if _is_iana(part):
                    return part
    except Exception:
        pass
    return None
