"""
Time Tool Class - Handle time-related operations
"""

import re, sys, copy
from datetime import datetime
from typing import Tuple, List, Optional, Dict
import pandas as pd
from datetime import datetime, timedelta

class TimeUtils:
    """Time Tool Class"""
    
    @staticmethod
    def parse_time(time_str: str) -> Optional[datetime]:
        """
        Parse time string to datetime object
        
        Args:
            time_str: Time string, format like "2025-06-06 07:05" or "07:05"
            
        Returns:
            datetime object, if parsing failed return None
        """
        if not time_str:
            return None
            
        try:
            # Try to parse complete time format "YYYY-MM-DD HH:MM"
            if len(time_str) > 10:
                return datetime.strptime(time_str, "%Y-%m-%d %H:%M")
            # Try to parse time format "HH:MM"
            else:
                # Use current date as default date
                current_date = datetime.now().strftime("%Y-%m-%d")
                full_time_str = f"{current_date} {time_str}"
                return datetime.strptime(full_time_str, "%Y-%m-%d %H:%M")
        except Exception as e:
            # print(f"Time parsing failed in parse_time: {time_str} - {e}")
            return None

    @staticmethod
    def extract_time_only(time_str: str) -> str:
        """
        Extract only hours and minutes from time string
        
        Args:
            time_str: Time string, format like "2025-06-06 07:05"
            
        Returns:
            Time string with only hours and minutes, format "HH:MM"
        """
        if not time_str:
            return ""
            
        try:
            # If it is already in HH:MM format
            if len(time_str) <= 5 and ":" in time_str:
                return time_str
            
            # Parse complete time format
            time_obj = TimeUtils.parse_time(time_str)
            if time_obj:
                return time_obj.strftime("%H:%M")
            else:
                return ""
        except Exception as e:
            print(f"提取时间失败: {time_str} - {e}")
            return ""
    
    @staticmethod
    def extract_time_for_comparison(time_str: str) -> int:
        """
        Extract minutes from time string, for time comparison
        
        Args:
            time_str: Time string, format like "2025-06-06 07:05" or "07:05"
            
        Returns:
            Minutes from midnight, for time comparison
        """
        if not time_str:
            return 0
            
        try:
            time_obj = TimeUtils.parse_time(time_str)
            if time_obj:
                # Return total minutes
                return time_obj.timestamp()
            else:
                return 0
        except Exception as e:
            print(f"提取比较时间失败: {time_str} - {e}")
            return 0
    
    @staticmethod
    def compare_times_later(time1: str, time2: str) -> int:
        """
        Compare two time strings, for example, 2025-06-06 07:05 and 14:30, compare 07:05 and 14:30
        
        Args:
            time1: First time string
            time2: Second time string
            
        Returns:
            -1: time1 < time2  
             0: time1 == time2  
             1: time1 > time2
        """
        if len(time1) == len(time2): # The time to compare contains days
            minutes1 = TimeUtils.extract_time_for_comparison(time1)
            minutes2 = TimeUtils.extract_time_for_comparison(time2)
        else: # The time to compare does not contain days
            minutes1 = TimeUtils.extract_time_for_comparison(f"{time1.split(' ')[-1]}")  # 2025-06-27 20:00
            minutes2 = TimeUtils.extract_time_for_comparison(f"{time2.split(' ')[-1]}")
        
        if minutes1 < minutes2:
            return -1
        elif minutes1 > minutes2:
            return 1
        else:
            return 0
    
    @staticmethod
    def time_operation_add(time: str, hour: float) -> str:
        """
        Time operation
        """
        time_obj = TimeUtils.parse_time(time)
        # If it is more than 24 hours, subtract 24 hours
        if time_obj:
            time_obj_new = time_obj + timedelta(hours=hour)
            if time_obj.day != time_obj_new.day:
                return "23:59"
            else:
                return time_obj_new.strftime("%H:%M")
        else:
            return time_obj

        
    @staticmethod
    def extract_hours(hours_str: str) -> Optional[float]:
        """
        Extract hours from time string
        
        Args:
            hours_str: Time string, format like "3.5H"
            
        Returns:
            Hours, if parsing failed return None
        """
        match = re.match(r"(\d+(\.\d+)?)H", hours_str)
        if match:
            return float(match.group(1))
        return None
    
    @staticmethod
    def get_time_of_day(time_str: str) -> Tuple[Optional[datetime], List[str]]:
        """
        Get time period based on time
        
        Args:
            time_str: Time string, format "YYYY-MM-DD HH:MM"
            
        Returns:
            Tuple[datetime, List[str]]: (Time object, time period list)
        """
        try:
            if len(time_str) == 5:
                time_obj = datetime.strptime(time_str, "%H:%M")
            else:
                time_obj = datetime.strptime(time_str, "%Y-%m-%d %H:%M")
            hour = time_obj.hour
            
            if 1 <= hour < 11:
                return time_obj, ["Morning", "上午"]
            elif 11 <= hour <= 12:
                return time_obj, ["Morning", "Afternoon", "上午", "下午"]
            elif 12 < hour < 17:
                return time_obj, ["Afternoon", "下午"]
            elif 17 <= hour <= 20:
                return time_obj, ["Evening", "Afternoon", "下午", "晚上"]
            else:
                return time_obj, ["Evening", "晚上"]
        except Exception as e:
            print(f"时间解析失败 in get_time_of_day: {time_str} - {e}")
            return None, ["Morning", "Afternoon", "Evening", "上午", "下午", "晚上"]
    
    @staticmethod
    def _time_period_strict(time, locale):
        if time <="12:00":
            if locale.lower().startswith('zh'):
                return ("morning",0)
            return ("上午",0)
        elif time <="18:00":
            if locale.lower().startswith('zh'):
                return ("afternoon",1)
            return ("下午",1)
        else:
            if locale.lower().startswith('zh'):
                return ("evening",2)
            return ("晚上",2)

    @staticmethod
    def find_less_than4(playhours_min_list: List[str], route_info: Dict) -> List[int]:
        """
        Find dates with less than 4 hours of playtime
        
        Args:
            playhours_min_list: Playtime list
            route_info: Route information
            
        Returns:
            Date index list
        """
        less_than_4 = []
        try:
            curelement2day = {}
            for ind, dayinfo in enumerate(route_info["route_info"]):
                dayindex = dayinfo["day_index"]
                curelement2day[ind] = dayindex
                
            for ind, hours in enumerate(playhours_min_list):
                if TimeUtils.extract_hours(hours) is not None and TimeUtils.extract_hours(hours) < 4.0:
                    less_than_4.append(curelement2day[ind])
                    
            less_than_4 = list(set(less_than_4))
        except Exception as e:
            print(f"查找少于4小时游玩时间时出错: {e}")
            
        return less_than_4 


def parse_poi_spendtime(spendtime):
    spendtime = spendtime.replace('天', ' 天')
    spendtime = spendtime.replace('小时', ' 小时')
    if "分钟" in spendtime:
        spendtime = spendtime.replace('分钟', ' 分钟')
    elif "分" in spendtime:
        spendtime = spendtime.replace('分', ' 分')
    try:
        timerange, unit = spendtime.strip().split(' ')
        if unit.lower() in ('hour', 'hours', '小时'):
            to_unit = 'h'
        elif unit.lower() in ('day', 'days', '天'):
            to_unit = 'D'
        elif unit.lower() in ('minute', 'minutes', '分钟', '分'):
            to_unit = 'T'
        else:
            print(f"not catched type in parse_poi_spendtime spendtime: {spendtime}, timerange: {timerange}, unit:{unit}")
            return pd.Timedelta(hours=1), pd.Timedelta(hours=1)
        if to_unit == 'D':
            return pd.Timedelta(hours=8 * float(timerange.split('-')[0])), \
                pd.Timedelta(hours=8 * float(timerange.split('-')[-1]))
        else:
            return pd.Timedelta('{}{}'.format(timerange.split('-')[0], to_unit)), \
                pd.Timedelta('{}{}'.format(timerange.split('-')[-1], to_unit))

    except Exception as e:
        # import traceback
        # traceback.print_exc()
        # traceback_str = ''.join(traceback.format_exception(*sys.exc_info()))
        # print("spendtime", spendtime)
        return pd.Timedelta(hours=1), pd.Timedelta(hours=1)


def parse_poi_opentime(opentime_rules):
    def _time_intersection(time_range1, time_range2):
        start1 = time_range1[0]
        end1 = time_range1[1]
        start2 = time_range2[0]
        end2 = time_range2[1]

        if start1 <= end2 and end1 >= start2:
            return True
        else:
            return False

    def _merge_time(all_time_range):
        origin_time_range = copy.deepcopy(all_time_range)
        update_flag = True
        while update_flag:
            update_flag = False
            new_time_range = []
            for tr in origin_time_range:
                for sr in new_time_range:
                    if tr[0] <= sr[1] and tr[1] >= sr[0]:
                        update_flag = True
                        sr[0], sr[1] = min(sr[0], tr[0]), max(sr[1], tr[1])
                        break
                else:
                    new_time_range.append(tr)
            origin_time_range = copy.deepcopy(new_time_range)
        return sorted(new_time_range, key=lambda x: x[0])

    today = datetime.now()
    available_date = datetime.now()+pd.Timedelta(days=30)
    current_year = datetime.now().year
    opentime_range = []
    for rule in opentime_rules:
        if rule['ruleType'] == 1:
            open_date_range = [[pd.to_datetime(datetime.strptime(i['start'], "%m/%d")),
                                pd.to_datetime(datetime.strptime(i['end'], "%m/%d"))] for i in rule['dateRangeList']]
            open_date_range = [[i.replace(year=current_year) for i in item] for item in open_date_range]
            open_date_range = [[i[0], i[1].replace(year=current_year + 1)] if i[0] > i[1] else i for i in
                               open_date_range]
            for date_range in open_date_range:
                if _time_intersection([today, available_date], date_range):
                    for i in rule['openTimeRuleInfoList']:
                        try:
                            start_time, end_time = i['description'].split('-')
                            opentime_range.append([pd.to_datetime(datetime.strptime(start_time, "%M:%S")),
                                                   pd.to_datetime(datetime.strptime(end_time, "%M:%S"))])
                        except:
                            continue
    if len(opentime_range) > 0:
        opentime_range = _merge_time(opentime_range)
        opentime = ','.join([f"{i[0].strftime('%M:%S')}-{i[1].strftime('%M:%S')}" for i in opentime_range])
    else:
        opentime = "00:00-23:59"
    return opentime


def _calculate_transport_hours(start_time_str, end_time_str):
    # Convert time string to time object
    start_time = datetime.strptime(start_time_str, "%Y-%m-%d %H:%M")
    end_time = datetime.strptime(end_time_str, "%Y-%m-%d %H:%M")

    # Check if it crosses the day
    if end_time.day != start_time.day:
        # Calculate the time difference from midnight to end_time
        total_time = datetime(start_time.year, start_time.month, start_time.day, 23, 59, 59) - start_time
        # total_time = end_time - datetime.strptime("00:00", "%H:%M")
    else:
        # Calculate the time difference directly
        total_time = end_time - start_time
    # Convert the time difference to hours
    hours = total_time.total_seconds() / 3600
    return hours


if __name__ == "__main__":
    time1 = "2025-08-31 20:25"
    time2 = "2025-09-01 02:25"
    print(TimeUtils.compare_times_later(time1, time2))

