"""
Period boundary calculation for recurring anomaly implementation.

Single-responsibility utility for calculating all period windows within 
job timeframes according to CloudZero period specifications.
"""

from datetime import datetime, timedelta
from typing import List, Tuple


def calculate_period_occurrences(
    job_start: datetime, 
    job_end: datetime, 
    period: str
) -> List[Tuple[datetime, datetime]]:
    """
    Calculate all period windows within job timeframe using backward calculation.
    
    For cumulative step changes, periods are calculated backwards from job end
    to ensure consistent timing across datasets of different lengths.
    
    Args:
        job_start: Start of generation job timeframe
        job_end: End of generation job timeframe  
        period: CloudZero period specification ("Last 30 Days" or "Last 90 Days")
        
    Returns:
        List of (period_start, period_end) tuples covering job timeframe
        
    Raises:
        ValueError: For unsupported period specifications
    """
    # Support both 30-day and 90-day periods for cumulative step changes
    if period == "Last 30 Days":
        period_length = 30
    elif period == "Last 90 Days":
        period_length = 90
    else:
        raise ValueError(f"Unsupported period: {period}. Only 'Last 30 Days' and 'Last 90 Days' are supported.")
    
    # Calculate periods backwards from job end for consistent timing
    periods = []
    current_end = job_end
    
    while True:
        current_start = current_end - timedelta(days=period_length - 1)  # period_length days including end
        
        # Stop if period starts before job start
        if current_start < job_start:
            break
            
        periods.append((current_start, current_end))
        current_end = current_start - timedelta(days=1)  # Next period ends day before this one starts
    
    # Return in chronological order
    return list(reversed(periods))


def calculate_anomaly_occurrences_in_job(
    job_start: datetime,
    job_end: datetime,
    period: str,
    day_offset: int,
    hour_offset: int = 0
) -> List[datetime]:
    """
    Calculate all anomaly occurrence timestamps within job timeframe.
    
    Given a period and day/hour offset, calculates when anomalies should
    occur across all period windows in the job timeframe.
    
    Args:
        job_start: Start of generation job timeframe
        job_end: End of generation job timeframe
        period: CloudZero period specification ("Last 30 Days" or "Last 90 Days")
        day_offset: Day offset within each period (15 for 30-day, 45 for 90-day periods)
        hour_offset: Hour offset within the day
        
    Returns:
        List of datetime objects when anomalies should occur
    """
    # Validate period (will raise ValueError if not supported)
    periods = calculate_period_occurrences(job_start, job_end, period)
    anomaly_times = []
    
    for period_start, period_end in periods:
        anomaly_time = period_start + timedelta(days=day_offset, hours=hour_offset)
        
        # Only include if anomaly time falls within this period and job bounds
        if period_start <= anomaly_time < period_end and anomaly_time < job_end:
            anomaly_times.append(anomaly_time)
    
    return anomaly_times