# -*- coding: utf-8 -*-
"""时区转换与日期范围工具。

默认时区：Asia/Shanghai（UTC+8），与业务数据库 timestamptz 对齐。
"""
import calendar
from datetime import datetime, date, timedelta
from dateutil import tz

SHANGHAI_TZ = tz.gettz("Asia/Shanghai")


def now_shanghai() -> datetime:
    """获取上海时区当前时间。"""
    return datetime.now(SHANGHAI_TZ)


def date_range(start: date, end: date) -> list[date]:
    """生成日期范围列表（含首尾）。

    start > end 时返回空列表。
    """
    if start > end:
        return []
    days = (end - start).days + 1
    return [start + timedelta(days=i) for i in range(days)]


# 营业日切点默认值（小时），与 .env BUSINESS_DAY_START_HOUR 对齐
DEFAULT_BUSINESS_DAY_START_HOUR = 8


def business_date(dt: datetime, day_start_hour: int = DEFAULT_BUSINESS_DAY_START_HOUR) -> date:
    """将时间戳归属到营业日。

    day_start_hour 之前的记录归属前一天。
    例：day_start_hour=8 时，07:59 归属前一天，08:00 归属当天。
    """
    if dt.hour < day_start_hour:
        return (dt - timedelta(days=1)).date()
    return dt.date()


def business_month(dt: datetime, day_start_hour: int = DEFAULT_BUSINESS_DAY_START_HOUR) -> date:
    """将时间戳归属到营业月（返回该月第一天）。

    当月1日 day_start_hour 之前的记录归属上月。
    """
    biz_d = business_date(dt, day_start_hour)
    return biz_d.replace(day=1)


def business_week_monday(dt: datetime, day_start_hour: int = DEFAULT_BUSINESS_DAY_START_HOUR) -> date:
    """将时间戳归属到营业周（返回该周周一日期）。

    周一 day_start_hour 之前的记录归属上周。
    """
    biz_d = business_date(dt, day_start_hour)
    return biz_d - timedelta(days=biz_d.weekday())


def biz_date_sql_expr(col: str, day_start_hour: int = DEFAULT_BUSINESS_DAY_START_HOUR) -> str:
    """生成 PostgreSQL 营业日归属 SQL 表达式。

    返回形如 DATE(col - INTERVAL '8 hours') 的字符串，
    用于替换原来的 DATE(col)。
    """
    return f"DATE({col} - INTERVAL '{day_start_hour} hours')"


def business_day_range(
    biz_date: date, day_start_hour: int = DEFAULT_BUSINESS_DAY_START_HOUR
) -> tuple[datetime, datetime]:
    """返回给定营业日的精确时间戳范围 [start, end)。

    start = biz_date 当天 day_start_hour:00（Asia/Shanghai）
    end   = biz_date 次日 day_start_hour:00（Asia/Shanghai）
    """
    start = datetime(biz_date.year, biz_date.month, biz_date.day,
                     day_start_hour, 0, 0, tzinfo=SHANGHAI_TZ)
    end = start + timedelta(days=1)
    return (start, end)


def business_week_range(
    week_monday: date, day_start_hour: int = DEFAULT_BUSINESS_DAY_START_HOUR
) -> tuple[datetime, datetime]:
    """返回给定营业周（周一）的精确时间戳范围 [start, end)。

    start = week_monday 当天 day_start_hour:00（Asia/Shanghai）
    end   = week_monday + 7天 day_start_hour:00（Asia/Shanghai）
    """
    start = datetime(week_monday.year, week_monday.month, week_monday.day,
                     day_start_hour, 0, 0, tzinfo=SHANGHAI_TZ)
    end = start + timedelta(days=7)
    return (start, end)


def business_month_range(
    month_first: date, day_start_hour: int = DEFAULT_BUSINESS_DAY_START_HOUR
) -> tuple[datetime, datetime]:
    """返回给定营业月（首日）的精确时间戳范围 [start, end)。

    start = month_first 当天 day_start_hour:00（Asia/Shanghai）
    end   = 次月1日 day_start_hour:00（Asia/Shanghai）
    """
    start = datetime(month_first.year, month_first.month, month_first.day,
                     day_start_hour, 0, 0, tzinfo=SHANGHAI_TZ)
    # 计算次月1日
    if month_first.month == 12:
        next_month_first = date(month_first.year + 1, 1, 1)
    else:
        next_month_first = date(month_first.year, month_first.month + 1, 1)
    end = datetime(next_month_first.year, next_month_first.month,
                   next_month_first.day, day_start_hour, 0, 0,
                   tzinfo=SHANGHAI_TZ)
    return (start, end)
