/**
 * SchedulingPolicy.java
 * 
 * Policy configuration for notification scheduling, fetching, and retry behavior.
 * 
 * This class is part of the Integration Point Refactor (PR1) SPI implementation.
 * It allows host apps to configure scheduling behavior including retry backoff,
 * prefetch timing, deduplication windows, and cache TTL.
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

package org.timesafari.dailynotification;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * Scheduling policy configuration
 * 
 * Controls how the plugin schedules fetches, handles retries, manages
 * deduplication, and enforces TTL policies.
 * 
 * This follows the TypeScript interface from src/types/content-fetcher.ts
 * and ensures consistency between JS and native configuration.
 */
public class SchedulingPolicy {
    
    /**
     * How early to prefetch before scheduled notification time (milliseconds)
     * 
     * Example: If set to 300000 (5 minutes), and notification is scheduled for
     * 8:00 AM, the fetch will be triggered at 7:55 AM.
     * 
     * Default: 5 minutes (300000ms)
     */
    @Nullable
    public Long prefetchWindowMs;
    
    /**
     * Retry backoff configuration (required)
     * 
     * Controls exponential backoff behavior for failed fetches
     */
    @NonNull
    public RetryBackoff retryBackoff;
    
    /**
     * Maximum items to fetch per batch
     * 
     * Limits the number of NotificationContent items that can be fetched
     * in a single operation. Helps prevent oversized responses.
     * 
     * Default: 50
     */
    @Nullable
    public Integer maxBatchSize;
    
    /**
     * Deduplication window (milliseconds)
     * 
     * Prevents duplicate notifications within this time window. Plugin
     * uses dedupeKey (or id) to detect duplicates.
     * 
     * Default: 24 hours (86400000ms)
     */
    @Nullable
    public Long dedupeHorizonMs;
    
    /**
     * Default cache TTL if item doesn't specify ttlSeconds (seconds)
     * 
     * Used when NotificationContent doesn't have ttlSeconds set.
     * Determines how long cached content remains valid.
     * 
     * Default: 6 hours (21600 seconds)
     */
    @Nullable
    public Integer cacheTtlSeconds;
    
    /**
     * Whether exact alarms are allowed (Android 12+)
     * 
     * Controls whether plugin should attempt to use exact alarms.
     * Requires SCHEDULE_EXACT_ALARM permission on Android 12+.
     * 
     * Default: false (use inexact alarms)
     */
    @Nullable
    public Boolean exactAlarmsAllowed;
    
    /**
     * Fetch timeout in milliseconds
     * 
     * Maximum time to wait for native fetcher to complete.
     * Plugin enforces this timeout when calling fetchContent().
     * 
     * Default: 30 seconds (30000ms)
     */
    @Nullable
    public Long fetchTimeoutMs;
    
    /**
     * Default constructor with required field
     * 
     * @param retryBackoff Retry backoff configuration (required)
     */
    public SchedulingPolicy(@NonNull RetryBackoff retryBackoff) {
        this.retryBackoff = retryBackoff;
    }
    
    /**
     * Retry backoff configuration
     * 
     * Controls exponential backoff behavior for retryable failures.
     * Delay = min(max(minMs, lastDelay * factor), maxMs) * (1 + jitterPct/100 * random)
     */
    public static class RetryBackoff {
        
        /**
         * Minimum delay between retries (milliseconds)
         * 
         * First retry will wait at least this long.
         * Default: 2000ms (2 seconds)
         */
        public long minMs;
        
        /**
         * Maximum delay between retries (milliseconds)
         * 
         * Retry delay will never exceed this value.
         * Default: 600000ms (10 minutes)
         */
        public long maxMs;
        
        /**
         * Exponential backoff multiplier
         * 
         * Each retry multiplies previous delay by this factor.
         * Example: factor=2 means delays: 2s, 4s, 8s, 16s, ...
         * Default: 2.0
         */
        public double factor;
        
        /**
         * Jitter percentage (0-100)
         * 
         * Adds randomness to prevent thundering herd.
         * Final delay = calculatedDelay * (1 + jitterPct/100 * random(0-1))
         * Default: 20 (20% jitter)
         */
        public int jitterPct;
        
        /**
         * Default constructor with sensible defaults
         */
        public RetryBackoff() {
            this.minMs = 2000;
            this.maxMs = 600000;
            this.factor = 2.0;
            this.jitterPct = 20;
        }
        
        /**
         * Constructor with all parameters
         * 
         * @param minMs Minimum delay (ms)
         * @param maxMs Maximum delay (ms)
         * @param factor Exponential multiplier
         * @param jitterPct Jitter percentage (0-100)
         */
        public RetryBackoff(long minMs, long maxMs, double factor, int jitterPct) {
            this.minMs = minMs;
            this.maxMs = maxMs;
            this.factor = factor;
            this.jitterPct = jitterPct;
        }
    }
    
    /**
     * Create default policy with sensible defaults
     * 
     * @return Default SchedulingPolicy instance
     */
    @NonNull
    public static SchedulingPolicy createDefault() {
        SchedulingPolicy policy = new SchedulingPolicy(new RetryBackoff());
        policy.prefetchWindowMs = 300000L; // 5 minutes
        policy.maxBatchSize = 50;
        policy.dedupeHorizonMs = 86400000L; // 24 hours
        policy.cacheTtlSeconds = 21600; // 6 hours
        policy.exactAlarmsAllowed = false;
        policy.fetchTimeoutMs = 30000L; // 30 seconds
        return policy;
    }
}

