"""
时间处理工具模块
提供各种时间格式转换和时间计算功能
"""
import datetime
import re
import os
import time
from typing import Optional, List, Tuple, Union
from .tools_log import console_log_debug


def trans_timestr_to_datetime(time_str: str) -> Optional[datetime.datetime]:
    """
    将时间字符串转换为datetime对象
    
    支持多种时间格式:
    - "2024-03-08T16:34" (ISO格式)
    - "2024-03-08" (日期格式)
    - "20240308163400" (紧凑型日期时间格式)
    - "202403081634" (紧凑型日期时间格式，分钟级)
    - "2024030816" (紧凑型日期时间格式，小时级)
    - "20240308" (紧凑型日期格式)
    
    Args:
        time_str (str): 时间字符串
        
    Returns:
        Optional[datetime.datetime]: 转换后的时间对象，失败时返回None
        
    Example:
        >>> trans_timestr_to_datetime("2024-03-08T16:34")
        datetime.datetime(2024, 3, 8, 16, 34)
    """
    if not time_str:
        return None
        
    datetime_target = None
    try:
        if "T" in time_str:
            # ISO格式: 2024-03-08T16:34
            if len(time_str) == 16:
                datetime_target = datetime.datetime.strptime(time_str, "%Y-%m-%dT%H:%M").replace(
                    second=0, microsecond=0)
        elif "-" in time_str:
            # 日期格式: 2024-03-08
            if len(time_str) == 10:
                datetime_target = datetime.datetime.strptime(time_str, "%Y-%m-%d").replace(
                    hour=0, minute=0, second=0, microsecond=0)
        else:
            # 紧凑型格式
            if len(time_str) == 14:
                # 20240308163400
                datetime_target = datetime.datetime.strptime(time_str, "%Y%m%d%H%M%S")
            elif len(time_str) == 12:
                # 202403081634
                datetime_target = datetime.datetime.strptime(time_str, '%Y%m%d%H%M')
            elif len(time_str) == 10:
                # 2024030816
                datetime_target = datetime.datetime.strptime(time_str, '%Y%m%d%H')
            elif len(time_str) == 8:
                # 20240308
                datetime_target = datetime.datetime.strptime(time_str, '%Y%m%d')
    except Exception as e:
        console_log_debug("时间转换异常！！！", time_str, onException=True)

    return datetime_target


def trans_timestr_to_stddatestr(time_str: str) -> Optional[str]:
    """
    将时间字符串转换为标准日期格式字符串
    
    Args:
        time_str (str): 时间字符串，格式应为 "%Y-%m-%d"
        
    Returns:
        Optional[str]: 标准日期格式字符串 "YYYY-MM-DD"，失败时返回None
        
    Example:
        >>> trans_timestr_to_stddatestr("2024-03-08")
        "2024-03-08"
    """
    try:
        return datetime.datetime.strptime(time_str, "%Y-%m-%d").strftime("%Y-%m-%d")
    except Exception:
        return None


def trans_datetime_to_describe(datetime_i: datetime.datetime) -> dict:
    """
    将datetime对象转换为描述性信息字典
    
    Args:
        datetime_i (datetime.datetime): datetime对象
        
    Returns:
        dict: 包含多种时间格式和描述的字典
            - datestr_Ymd: "YYYY-MM-DD"格式
            - datestr_BdY: "Month DD, YYYY"格式
            - datetimestr_Ymd_HMS: "YYYY-MM-DD HH:MM:SS"格式
            - weekday: 中文星期描述
            - workday: 工作日/周末标识
    """
    describe_dict = {}
    describe_dict["datestr_Ymd"] = datetime_i.strftime("%Y-%m-%d")
    describe_dict["datestr_BdY"] = datetime_i.strftime("%B %d, %Y")  # May 21, 2017
    describe_dict["datetimestr_Ymd_HMS"] = datetime_i.strftime("%Y-%m-%d %H:%M:%S")
    
    weekday_map = {
        0: ("星期一", "工作日"),
        1: ("星期二", "工作日"),
        2: ("星期三", "工作日"),
        3: ("星期四", "工作日"),
        4: ("星期五", "工作日"),
        5: ("星期六", "周末"),
        6: ("星期日", "周末")
    }
    
    weekday, workday = weekday_map[datetime_i.weekday()]
    describe_dict["weekday"] = weekday
    describe_dict["workday"] = workday
    
    return describe_dict


def get_week_dates(std_datetime: datetime.datetime = None) -> List[datetime.date]:
    """
    获取指定日期所在周的日期列表
    
    Args:
        std_datetime (datetime.datetime, optional): 指定日期，默认为当前日期
        
    Returns:
        List[datetime.date]: 一周七天的日期列表（周一到周日）
    """
    if std_datetime is None:
        std_datetime = datetime.datetime.now()
        
    # 计算本周一日期
    monday = std_datetime - datetime.timedelta(days=std_datetime.weekday())
    return [(monday + datetime.timedelta(days=i)).date() for i in range(7)]


def get_week_range(std_datetime: datetime.datetime = None, 
                   last: bool = False) -> Tuple[datetime.datetime, datetime.datetime]:
    """
    获取指定日期所在周的开始和结束时间范围
    
    Args:
        std_datetime (datetime.datetime, optional): 指定日期，默认为当前日期
        last (bool): 是否获取上周范围
        
    Returns:
        Tuple[datetime.datetime, datetime.datetime]: (开始时间, 结束时间)元组
    """
    if std_datetime is None:
        std_datetime = datetime.datetime.now()
        
    if last:
        # 计算上周一
        now_monday = std_datetime - datetime.timedelta(days=std_datetime.weekday())
        monday = now_monday - datetime.timedelta(days=7)
    else:
        # 计算本周一
        monday = std_datetime - datetime.timedelta(days=std_datetime.weekday())
        
    # 设置时间为 00:00:00
    start_time = monday.replace(hour=0, minute=0, second=0, microsecond=0)
    # 设置结束时间为周日 23:59:59
    end_time = (monday + datetime.timedelta(days=6)).replace(
        hour=23, minute=59, second=59, microsecond=999999)
    
    return (start_time, end_time)


def get_month_range(std_datetime: datetime.datetime = None, 
                    last: bool = False) -> Tuple[datetime.date, datetime.date]:
    """
    获取指定日期所在月的开始和结束日期范围
    
    Args:
        std_datetime (datetime.datetime, optional): 指定日期，默认为当前日期
        last (bool): 是否获取上月范围
        
    Returns:
        Tuple[datetime.date, datetime.date]: (开始日期, 结束日期)元组
    """
    if std_datetime is None:
        std_datetime = datetime.datetime.now()
        
    if last:
        # 计算上月第一天
        first_day = (std_datetime.replace(day=1) - datetime.timedelta(days=1)).replace(day=1)
    else:
        # 本月第一天
        first_day = std_datetime.replace(day=1)
        
    # 计算月末日期
    if first_day.month == 12:
        end_day = first_day.replace(year=first_day.year + 1, month=1, day=1) - datetime.timedelta(days=1)
    else:
        end_day = first_day.replace(month=first_day.month + 1, day=1) - datetime.timedelta(days=1)
        
    return (first_day.date(), end_day.date())


def get_quarter_range(std_datetime: datetime.datetime = None, 
                      last: bool = False) -> Tuple[datetime.date, datetime.date]:
    """
    获取指定日期所在季度的开始和结束日期范围
    
    Args:
        std_datetime (datetime.datetime, optional): 指定日期，默认为当前日期
        last (bool): 是否获取上季度范围
        
    Returns:
        Tuple[datetime.date, datetime.date]: (开始日期, 结束日期)元组
    """
    if std_datetime is None:
        std_datetime = datetime.datetime.now()
        
    if last:
        # 上个季度的标记日期
        mark_date = std_datetime.replace(day=1, month=(std_datetime.month - 1) // 3 * 3 + 1) - datetime.timedelta(days=1)
    else:
        mark_date = std_datetime
        
    # 季度第一天
    first_day = mark_date.replace(day=1, month=(mark_date.month - 1) // 3 * 3 + 1)
    # 季度最后一天
    end_month_first = first_day.replace(month=first_day.month + 2, day=1)
    if end_month_first.month > 12:
        end_month_first = end_month_first.replace(year=end_month_first.year + 1, month=end_month_first.month - 12)
        
    if end_month_first.month == 12:
        end_day = end_month_first.replace(year=end_month_first.year + 1, month=1, day=1) - datetime.timedelta(days=1)
    else:
        end_day = end_month_first.replace(month=end_month_first.month + 1, day=1) - datetime.timedelta(days=1)
        
    return (first_day.date(), end_day.date())


def get_year_range(std_datetime: datetime.datetime = None, 
                   last: bool = False) -> Tuple[datetime.date, datetime.date]:
    """
    获取指定日期所在年的开始和结束日期范围
    
    Args:
        std_datetime (datetime.datetime, optional): 指定日期，默认为当前日期
        last (bool): 是否获取去年范围
        
    Returns:
        Tuple[datetime.date, datetime.date]: (开始日期, 结束日期)元组
    """
    if std_datetime is None:
        std_datetime = datetime.datetime.now()
        
    if last:
        # 去年第一天
        first_day = std_datetime.replace(year=std_datetime.year - 1, month=1, day=1)
    else:
        # 今年第一天
        first_day = std_datetime.replace(year=std_datetime.year, month=1, day=1)
        
    # 今年最后一天
    end_day = std_datetime.replace(year=std_datetime.year, month=12, day=31)
    
    return (first_day.date(), end_day.date())


def get_offset_date(offset: int = 1) -> datetime.date:
    """
    获取相对于今天的偏移日期
    
    Args:
        offset (int): 偏移天数，正数表示未来，负数表示过去，默认为1
        
    Returns:
        datetime.date: 偏移后的日期
    """
    return datetime.date.today() + datetime.timedelta(days=offset)


def create_timestamp_mark(digit: int = 5) -> str:
    """
    创建时间戳标记（用于文件名等场景）
    
    Args:
        digit (int): 返回的位数，默认为5位
        
    Returns:
        str: 时间戳标记字符串
    """
    timemark = int(time.time() * 1000000)  # 去掉小数位
    timemark_str = str(timemark)[-digit:]
    return timemark_str


def create_time_mark() -> str:
    """
    创建时间标记（精确到毫秒，用于临时文件名等场景）
    
    Returns:
        str: 17位时间戳字符串，格式为"YYYYMMDDHHMMSS.SSS"
    """
    return datetime.datetime.now().strftime("%Y%m%d%H%M%S.%f")[:-3]


def analyse_filename_time(filename: str) -> Optional[datetime.datetime]:
    """
    从文件名中提取时间信息
    
    Args:
        filename (str): 文件名
        
    Returns:
        Optional[datetime.datetime]: 提取到的时间对象，未找到或解析失败时返回None
    """
    # 清理文件名中的分隔符
    cleaned_filename = filename.replace("-", "").replace("_", "").replace(".", "").replace(" ", "").replace(":", "")
    
    # 匹配8-14位数字
    match_result = re.search(r"\d{8,14}", cleaned_filename)

    the_time = None
    if match_result:
        time_str = match_result.group()
        try:
            if len(time_str) == 14:
                # YYYYMMDDHHMMSS
                the_time = datetime.datetime.strptime(time_str, "%Y%m%d%H%M%S")
            elif len(time_str) == 12:
                # YYYYMMDDHHMM
                the_time = datetime.datetime.strptime(time_str, '%Y%m%d%H%M')
            elif len(time_str) == 10:
                # YYYYMMDDHH
                the_time = datetime.datetime.strptime(time_str, '%Y%m%d%H')
            elif len(time_str) == 8:
                # YYYYMMDD
                the_time = datetime.datetime.strptime(time_str, '%Y%m%d')
        except Exception as e:
            # 解析失败，保持the_time为None
            pass
            
    return the_time


def analyse_fileattr_time(file_path: str) -> Optional[datetime.datetime]:
    """
    从文件属性中获取修改时间
    
    Args:
        file_path (str): 文件路径
        
    Returns:
        Optional[datetime.datetime]: 文件修改时间，失败时返回None
    """
    the_time = None
    try:
        time_stamp = os.path.getmtime(file_path)
        the_time = datetime.datetime.fromtimestamp(time_stamp)
    except Exception as e:
        # 获取失败，保持the_time为None
        pass
        
    return the_time