"""
Time utility functions for TimeTrack application.
Includes time rounding functionality.
"""

from datetime import datetime, timedelta
import math


def round_time_to_interval(dt, interval_minutes, round_to_nearest=True):
    """
    Round a datetime to the specified interval.
    
    Args:
        dt (datetime): The datetime to round
        interval_minutes (int): The interval in minutes (15, 30, etc.)
        round_to_nearest (bool): If True, round to nearest interval; if False, round up
        
    Returns:
        datetime: The rounded datetime
    """
    if interval_minutes == 0:
        return dt  # No rounding
    
    # Calculate the number of minutes from midnight
    minutes_from_midnight = dt.hour * 60 + dt.minute
    
    if round_to_nearest:
        # Round to nearest interval
        rounded_minutes = round(minutes_from_midnight / interval_minutes) * interval_minutes
    else:
        # Round up to next interval
        rounded_minutes = math.ceil(minutes_from_midnight / interval_minutes) * interval_minutes
    
    # Convert back to hours and minutes
    rounded_hour = int(rounded_minutes // 60)
    rounded_minute = int(rounded_minutes % 60)
    
    # Handle case where rounding goes to next day
    if rounded_hour >= 24:
        rounded_hour = 0
        dt = dt + timedelta(days=1)
    
    # Create new datetime with rounded time (keep seconds as 0)
    return dt.replace(hour=rounded_hour, minute=rounded_minute, second=0, microsecond=0)


def round_duration_to_interval(duration_seconds, interval_minutes, round_to_nearest=True):
    """
    Round a duration to the specified interval.
    
    Args:
        duration_seconds (int): The duration in seconds
        interval_minutes (int): The interval in minutes (15, 30, etc.)
        round_to_nearest (bool): If True, round to nearest interval; if False, round up
        
    Returns:
        int: The rounded duration in seconds
    """
    if interval_minutes == 0:
        return duration_seconds  # No rounding
    
    # Convert to minutes
    duration_minutes = duration_seconds / 60
    interval_seconds = interval_minutes * 60
    
    if round_to_nearest:
        # Round to nearest interval
        rounded_intervals = round(duration_minutes / interval_minutes)
    else:
        # Round up to next interval
        rounded_intervals = math.ceil(duration_minutes / interval_minutes)
    
    return int(rounded_intervals * interval_seconds)


def get_user_rounding_settings(user):
    """
    Get the time rounding settings for a user.
    
    Args:
        user: The user object
        
    Returns:
        tuple: (interval_minutes, round_to_nearest)
    """
    # Handle both new UserPreferences model and old WorkConfig fallback
    try:
        # First try new UserPreferences model
        from models import UserPreferences
        preferences = UserPreferences.query.filter_by(user_id=user.id).first()
        if preferences:
            return preferences.time_rounding_minutes, preferences.round_to_nearest
        
        # Fallback to old WorkConfig if no UserPreferences exists
        work_config = getattr(user, 'work_config', None)
        if work_config:
            return getattr(work_config, 'time_rounding_minutes', 0), getattr(work_config, 'round_to_nearest', True)
            
    except Exception:
        pass
    
    return 0, True  # Default: no rounding, round to nearest


def apply_time_rounding(arrival_time, departure_time, user):
    """
    Apply time rounding to arrival and departure times based on user settings.
    
    Args:
        arrival_time (datetime): The original arrival time
        departure_time (datetime): The original departure time
        user: The user object
        
    Returns:
        tuple: (rounded_arrival_time, rounded_departure_time)
    """
    interval_minutes, round_to_nearest = get_user_rounding_settings(user)
    
    if interval_minutes == 0:
        return arrival_time, departure_time  # No rounding
    
    # Round arrival time (typically round up to start billing later)
    rounded_arrival = round_time_to_interval(arrival_time, interval_minutes, round_to_nearest)
    
    # Round departure time (typically round up to bill more time)
    rounded_departure = round_time_to_interval(departure_time, interval_minutes, not round_to_nearest)
    
    # Ensure departure is still after arrival
    if rounded_departure <= rounded_arrival:
        # Add one interval to departure time
        rounded_departure = rounded_departure + timedelta(minutes=interval_minutes)
    
    return rounded_arrival, rounded_departure


def format_rounding_interval(interval_minutes):
    """
    Format the rounding interval for display.
    
    Args:
        interval_minutes (int): The interval in minutes
        
    Returns:
        str: Formatted interval description
    """
    if interval_minutes == 0:
        return "No rounding"
    elif interval_minutes == 15:
        return "15 minutes"
    elif interval_minutes == 30:
        return "30 minutes"
    elif interval_minutes == 60:
        return "1 hour"
    else:
        return f"{interval_minutes} minutes"


def get_available_rounding_options():
    """
    Get the available time rounding options.
    
    Returns:
        list: List of tuples (value, label)
    """
    return [
        (0, "No rounding"),
        (15, "15 minutes"),
        (30, "30 minutes"),
        (60, "1 hour")
    ]


# Date/Time Formatting Functions

def get_available_date_formats():
    """
    Get the available date format options.
    
    Returns:
        list: List of tuples (value, label, example)
    """
    return [
        ('ISO', 'ISO Format (YYYY-MM-DD)', '2024-12-25'),
        ('US', 'US Format (MM/DD/YYYY)', '12/25/2024'),
        ('EU', 'European Format (DD/MM/YYYY)', '25/12/2024'),
        ('UK', 'UK Format (DD/MM/YYYY)', '25/12/2024'),
        ('Readable', 'Readable Format (Dec 25, 2024)', 'Dec 25, 2024'),
        ('Full', 'Full Format (December 25, 2024)', 'December 25, 2024')
    ]


def format_date_by_preference(dt, date_format='ISO'):
    """
    Format a date according to user preference.
    
    Args:
        dt (datetime): The datetime to format
        date_format (str): The format preference
        
    Returns:
        str: Formatted date string
    """
    if dt is None:
        return ''
    
    format_map = {
        'ISO': '%Y-%m-%d',
        'US': '%m/%d/%Y',
        'EU': '%d/%m/%Y',
        'UK': '%d/%m/%Y',
        'Readable': '%b %d, %Y',
        'Full': '%B %d, %Y'
    }
    
    format_string = format_map.get(date_format, '%Y-%m-%d')
    return dt.strftime(format_string)


def format_time_by_preference(dt, time_format_24h=True):
    """
    Format a time according to user preference.
    
    Args:
        dt (datetime): The datetime to format
        time_format_24h (bool): True for 24h format, False for 12h (AM/PM)
        
    Returns:
        str: Formatted time string
    """
    if dt is None:
        return ''
    
    if time_format_24h:
        return dt.strftime('%H:%M:%S')
    else:
        return dt.strftime('%I:%M:%S %p')


def format_datetime_by_preference(dt, date_format='ISO', time_format_24h=True):
    """
    Format a datetime according to user preferences.
    
    Args:
        dt (datetime): The datetime to format
        date_format (str): The date format preference
        time_format_24h (bool): True for 24h format, False for 12h (AM/PM)
        
    Returns:
        str: Formatted datetime string
    """
    if dt is None:
        return ''
    
    date_part = format_date_by_preference(dt, date_format)
    time_part = format_time_by_preference(dt, time_format_24h)
    return f"{date_part} {time_part}"


def format_time_short_by_preference(dt, time_format_24h=True):
    """
    Format a time without seconds according to user preference.
    
    Args:
        dt (datetime): The datetime to format
        time_format_24h (bool): True for 24h format, False for 12h (AM/PM)
        
    Returns:
        str: Formatted time string (without seconds)
    """
    if dt is None:
        return ''
    
    if time_format_24h:
        return dt.strftime('%H:%M')
    else:
        return dt.strftime('%I:%M %p')


def get_user_format_settings(user):
    """
    Get the date/time format settings for a user.
    
    Args:
        user: The user object
        
    Returns:
        tuple: (date_format, time_format_24h)
    """
    # Handle both new UserPreferences model and old WorkConfig fallback
    try:
        # First try new UserPreferences model
        from models import UserPreferences
        preferences = UserPreferences.query.filter_by(user_id=user.id).first()
        if preferences:
            return preferences.date_format or 'ISO', preferences.time_format_24h
        
        # Fallback to old WorkConfig if no UserPreferences exists
        work_config = getattr(user, 'work_config', None)
        if work_config:
            return getattr(work_config, 'date_format', 'ISO') or 'ISO', getattr(work_config, 'time_format_24h', True)
            
    except Exception:
        pass
    
    return 'ISO', True  # Default: ISO date format, 24h time


def format_duration_readable(duration_seconds):
    """
    Format duration in a readable format (e.g., "2h 30m").
    
    Args:
        duration_seconds (int): Duration in seconds
        
    Returns:
        str: Formatted duration string
    """
    if duration_seconds is None or duration_seconds == 0:
        return '0m'
    
    hours = duration_seconds // 3600
    minutes = (duration_seconds % 3600) // 60
    seconds = duration_seconds % 60
    
    parts = []
    if hours > 0:
        parts.append(f"{hours}h")
    if minutes > 0:
        parts.append(f"{minutes}m")
    if seconds > 0 and hours == 0:  # Only show seconds if less than an hour
        parts.append(f"{seconds}s")
    
    return ' '.join(parts) if parts else '0m'


def format_duration_decimal(duration_seconds):
    """
    Format duration as decimal hours (e.g., "2.5" for 2h 30m).
    
    Args:
        duration_seconds (int): Duration in seconds
        
    Returns:
        str: Formatted duration as decimal hours
    """
    if duration_seconds is None:
        return '0.00'
    
    hours = duration_seconds / 3600
    return f"{hours:.2f}"