"""Cấu hình logging tập trung cho DSCons ERP.

Vì sao cần module này (sự cố 05/10/2026):
    Ứng dụng chưa từng cấu hình logging. Python khi đó chỉ in WARNING+ ra stderr qua handler
    dự phòng `logging.lastResort` - không có giờ, mức log hay tên module - còn toàn bộ INFO
    (captcha đồng thuận, phiên đồng bộ thành công, số hoá đơn nạp...) bị nuốt mất.
    Khi hệ thống chạy tốt, `docker logs dscons-backend` gần như chỉ còn log truy cập HTTP.

Thiết kế:
    - Gắn 1 StreamHandler (stdout) vào ROOT logger -> mọi logger con (`app.*`, `dscons.*`)
      propagate lên đây; pytest `caplog` vẫn hoạt động bình thường.
    - Root ở mức WARNING để chặn INFO ồn ào của thư viện ngoài (httpx in mỗi request...);
      riêng namespace của ứng dụng (`app`, `dscons`) mở ở mức DSCONS_LOG_LEVEL (mặc định INFO).
    - Logger của uvicorn có handler riêng & propagate=False -> không bị in trùng.
    - Idempotent: uvicorn --reload import lại app.main trong tiến trình mới, gọi nhiều lần
      vẫn chỉ có đúng 1 handler (nhận diện qua tên DSCONS_HANDLER_NAME).
    - Giờ hiển thị theo Việt Nam (GMT+7) cho dễ đối chiếu với email cảnh báo.
"""

from __future__ import annotations

import logging
import os
import sys
from datetime import datetime
from typing import TextIO

from app.core.vn_time import VN_TZ, VN_TZ_LABEL

DSCONS_HANDLER_NAME = "dscons-console"
APP_LOGGER_NAMESPACES: tuple[str, ...] = ("app", "dscons")
DEFAULT_APP_LOG_LEVEL = "INFO"
THIRD_PARTY_LOG_LEVEL = logging.WARNING
LOG_FORMAT = "%(asctime)s %(levelname)s [%(name)s] %(message)s"


class VnTimeFormatter(logging.Formatter):
    """Formatter in thời gian theo giờ VN: 'YYYY-mm-dd HH:MM:SS (GMT+7)'."""

    def formatTime(self, record: logging.LogRecord, datefmt: str | None = None) -> str:  # noqa: N802
        vn_dt = datetime.fromtimestamp(record.created, tz=VN_TZ)
        return f"{vn_dt.strftime(datefmt or '%Y-%m-%d %H:%M:%S')} {VN_TZ_LABEL}"


def _resolve_app_level() -> int:
    """Đọc mức log từ biến môi trường DSCONS_LOG_LEVEL (DEBUG/INFO/WARNING/...), sai -> INFO."""
    raw = (os.getenv("DSCONS_LOG_LEVEL") or DEFAULT_APP_LOG_LEVEL).strip().upper()
    level = logging.getLevelName(raw)
    return level if isinstance(level, int) else logging.INFO


def configure_logging(stream: TextIO | None = None) -> logging.Handler:
    """Cài đặt (hoặc cập nhật) handler console của DSCons; an toàn khi gọi nhiều lần."""
    root = logging.getLogger()
    handler = next((h for h in root.handlers if h.get_name() == DSCONS_HANDLER_NAME), None)
    target_stream = stream or sys.stdout

    if handler is None:
        handler = logging.StreamHandler(target_stream)
        handler.set_name(DSCONS_HANDLER_NAME)
        root.addHandler(handler)
    elif isinstance(handler, logging.StreamHandler) and handler.stream is not target_stream:
        handler.setStream(target_stream)

    handler.setFormatter(VnTimeFormatter(LOG_FORMAT))
    root.setLevel(THIRD_PARTY_LOG_LEVEL)

    app_level = _resolve_app_level()
    for namespace in APP_LOGGER_NAMESPACES:
        logging.getLogger(namespace).setLevel(app_level)
    return handler
