# from typing import Optional
# from datetime import datetime, timedelta
# from analogai.foundation.core.value_objects.time import Time
# from analogai.foundation.common.utils.time_utils.tense import Tense
# from analogai.foundation.common.utils.time_utils.time_converter import TimeConverter
# from analogai.foundation.common.utils.time_utils.relative_time_formatter import RelativeTimeFormatter
# from analogai.foundation.common.utils.time_utils.timezone_utils import TimezoneUtils


# class TimeFormatter:
    
#     @staticmethod
#     def has_time_data(time_obj: Optional[Time]) -> bool:
#         return TimeConverter.has_time_data(time_obj)
    
#     @staticmethod
#     def determine_tense(time_obj: Optional[Time], reference_time: Optional[datetime] = None, timezone: Optional[str] = None) -> Tense:
#         if not TimeFormatter.has_time_data(time_obj):
#             return Tense.PRESENT
        
#         reference_time = TimezoneUtils.get_timezone_aware_datetime(timezone, reference_time)
        
#         time_date = TimeConverter.to_datetime(time_obj, reference_time)
#         if time_date is None:
#             return Tense.PRESENT
        
#         if time_date.tzinfo is None:
#             time_date = time_date.replace(tzinfo=reference_time.tzinfo)
        
#         has_specific_time = time_obj.hour is not None or time_obj.minute is not None
        
#         time_date_only = time_date.date()
#         reference_date_only = reference_time.date()
        
#         if time_date_only < reference_date_only:
#             return Tense.PAST
#         elif time_date_only > reference_date_only:
#             return Tense.FUTURE
#         else:
#             if has_specific_time and time_date < reference_time:
#                 return Tense.PAST
#             else:
#                 return Tense.PRESENT
    
#     @staticmethod
#     def format_natural_language(time_obj: Optional[Time], reference_time: Optional[datetime] = None, timezone: Optional[str] = None) -> str:
#         if not TimeFormatter.has_time_data(time_obj):
#             return ""
        
#         reference_time = TimezoneUtils.get_timezone_aware_datetime(timezone, reference_time)
        
#         time_date = TimeConverter.to_datetime(time_obj, reference_time)
#         if time_date is None:
#             return RelativeTimeFormatter._format_absolute(time_obj)
        
#         if time_date.tzinfo is None:
#             time_date = time_date.replace(tzinfo=reference_time.tzinfo)
        
#         has_specific_time = time_obj.hour is not None or time_obj.minute is not None
#         has_year = time_obj.year is not None
#         has_month = time_obj.month is not None
#         has_day = time_obj.day is not None
        
#         time_date_only = time_date.date()
#         reference_date_only = reference_time.date()
#         days_diff = (time_date_only - reference_date_only).days
        
#         if not has_specific_time:
#             if days_diff == 0:
#                 return "today"
#             elif days_diff == -1:
#                 return "yesterday"
#             elif days_diff == 1:
#                 return "tomorrow"
#             else:
#                 if has_year and has_month and has_day:
#                     weekday_phrase = TimeFormatter._format_weekday_phrase(time_date_only, days_diff)
#                     if weekday_phrase:
#                         return weekday_phrase
#                     return RelativeTimeFormatter._format_absolute(time_obj)
#                 delta = timedelta(days=abs(days_diff))
#                 if days_diff < 0:
#                     return TimeFormatter._format_past_time(delta, time_date, reference_time, time_obj)
#                 else:
#                     return TimeFormatter._format_future_time(delta, time_date, reference_time, time_obj)

#         if has_year and has_month and has_day and days_diff not in (0, -1, 1):
#             weekday_phrase = TimeFormatter._format_weekday_phrase(time_date_only, days_diff)
#             if weekday_phrase:
#                 return weekday_phrase
#             return RelativeTimeFormatter._format_absolute(time_obj)
        
#         if days_diff == 0 and time_obj.hour is not None and time_obj.hour == reference_time.hour and time_obj.minute is None:
#             return "now"
        
#         delta = time_date - reference_time
#         total_seconds = delta.total_seconds()
        
#         if total_seconds > 0:
#             return TimeFormatter._format_future_time(delta, time_date, reference_time, time_obj)
#         elif total_seconds < 0:
#             return TimeFormatter._format_past_time(abs(delta), time_date, reference_time, time_obj)
#         else:
#             return "today"
    
#     @staticmethod
#     def format_for_range(time_obj: Optional[Time], reference_time: Optional[datetime] = None, timezone: Optional[str] = None) -> str:
#         reference_time = TimezoneUtils.get_timezone_aware_datetime(timezone, reference_time)
#         return RelativeTimeFormatter.format_for_range(time_obj, reference_time)
    
#     @staticmethod
#     def _format_future_time(delta: timedelta, time_date: datetime, reference: datetime, time_obj: Time) -> str:
#         time_date_only = time_date.date()
#         reference_date_only = reference.date()
#         days_diff = (time_date_only - reference_date_only).days
        
#         has_specific_time = time_obj.hour is not None or time_obj.minute is not None
#         total_seconds = delta.total_seconds()
        
#         if days_diff == 1:
#             if has_specific_time and total_seconds < 86400:
#                 if total_seconds < 3600:
#                     minutes = int(total_seconds / 60)
#                     if minutes == 1:
#                         return "in 1 minute"
#                     else:
#                         return f"in {minutes} minutes"
#                 else:
#                     hours = int(total_seconds / 3600)
#                     remaining_seconds = total_seconds % 3600
#                     minutes = int(remaining_seconds / 60)
                    
#                     if hours > 0 and minutes > 0:
#                         if hours == 1 and minutes == 1:
#                             return "in 1 hour and 1 minute"
#                         elif hours == 1:
#                             return f"in 1 hour and {minutes} minutes"
#                         elif minutes == 1:
#                             return f"in {hours} hours and 1 minute"
#                         else:
#                             return f"in {hours} hours and {minutes} minutes"
#                     elif hours > 0:
#                         if hours == 1:
#                             return "in 1 hour"
#                         else:
#                             return f"in {hours} hours"
#             return "tomorrow"
        
#         if total_seconds < 3600:
#             minutes = int(total_seconds / 60)
#             if minutes == 0:
#                 return "in less than a minute"
#             elif minutes == 1:
#                 return "in 1 minute"
#             else:
#                 return f"in {minutes} minutes"
        
#         elif total_seconds < 86400:
#             hours = int(total_seconds / 3600)
#             remaining_seconds = total_seconds % 3600
#             minutes = int(remaining_seconds / 60)
            
#             if hours > 0 and minutes > 0:
#                 if hours == 1 and minutes == 1:
#                     return "in 1 hour and 1 minute"
#                 elif hours == 1:
#                     return f"in 1 hour and {minutes} minutes"
#                 elif minutes == 1:
#                     return f"in {hours} hours and 1 minute"
#                 else:
#                     return f"in {hours} hours and {minutes} minutes"
#             elif hours > 0:
#                 if hours == 1:
#                     return "in 1 hour"
#                 else:
#                     return f"in {hours} hours"
#             elif minutes > 0:
#                 if minutes == 1:
#                     return "in 1 minute"
#                 else:
#                     return f"in {minutes} minutes"
#         elif days_diff < 7:
#             return f"in {days_diff} days"
#         elif days_diff < 14:
#             return "next week"
#         elif days_diff < 30:
#             weeks = days_diff // 7
#             return f"in {weeks} weeks"
#         elif days_diff < 60:
#             return "next month"
#         elif days_diff < 365:
#             months = days_diff // 30
#             if months == 1:
#                 return "next month"
#             return f"in {months} months"
#         else:
#             years = days_diff // 365
#             if years == 1:
#                 return "next year"
#             else:
#                 return f"in {years} years"
    
#     @staticmethod
#     def _format_past_time(delta: timedelta, time_date: datetime, reference: datetime, time_obj: Time) -> str:
#         total_seconds = delta.total_seconds()
        
#         if total_seconds < 3600:
#             minutes = int(total_seconds / 60)
#             if minutes == 0:
#                 return "just now"
#             elif minutes == 1:
#                 return "1 minute ago"
#             else:
#                 return f"{minutes} minutes ago"
        
#         hours = int(total_seconds / 3600)
        
#         time_date_only = time_date.date()
#         reference_date_only = reference.date()
        
#         if time_date_only == reference_date_only:
#             if hours <= 6:
#                 if hours == 1:
#                     return "1 hour ago"
#                 return f"{hours} hours ago"
#             return "today"
        
#         days_diff = (reference_date_only - time_date_only).days
        
#         if days_diff == 1:
#             return "yesterday"
#         elif days_diff < 7:
#             return f"{days_diff} days ago"
#         elif days_diff < 14:
#             return "last week"
#         elif days_diff < 30:
#             weeks = days_diff // 7
#             return f"{weeks} weeks ago"
#         elif days_diff < 60:
#             return "last month"
#         elif days_diff < 365:
#             months = days_diff // 30
#             if months == 1:
#                 return "last month"
#             return f"{months} months ago"
#         else:
#             years = days_diff // 365
#             if years == 1:
#                 return "last year"
#             if years > 10:
#                 return str(time_date.year)
#             return f"{years} years ago"

#     @staticmethod
#     def _format_weekday_phrase(time_date_only, days_diff: int) -> Optional[str]:
#         if days_diff == 0:
#             return "today"
#         if abs(days_diff) > 7:
#             return None
#         weekday = time_date_only.strftime("%A")
#         if days_diff > 0:
#             if days_diff == 7:
#                 return f"next {weekday}"
#             return f"this {weekday}"
#         if days_diff == -7:
#             return f"last {weekday}"
#         return f"last {weekday}"
    
#     @staticmethod
#     def is_relative_date(time_obj: Optional[Time], reference_time: Optional[datetime] = None) -> bool:
#         if not TimeFormatter.has_time_data(time_obj):
#             return False
        
#         if reference_time is None:
#             reference_time = datetime.now()
        
#         time_date = TimeConverter.to_datetime(time_obj, reference_time)
#         if time_date is None:
#             return False
        
#         time_date_only = time_date.date()
#         reference_date_only = reference_time.date()
        
#         tomorrow = reference_date_only + timedelta(days=1)
#         yesterday = reference_date_only - timedelta(days=1)
        
#         return time_date_only == reference_date_only or time_date_only == tomorrow or time_date_only == yesterday
