package com.social.media.domain.bot.service;

import com.social.media.domain.bot.aggregate.Bot;
import com.social.media.domain.bot.valueobject.BotConfiguration;
import com.social.media.domain.bot.valueobject.BotType;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;

import java.time.LocalDateTime;
import java.time.LocalTime;

/**
 * Domain service for bot scheduling and execution management
 */
public class BotSchedulingService {
    
    public LocalDateTime calculateNextExecution(Bot bot) {
        if (!bot.isActive()) {
            return null;
        }
        
        BotConfiguration config = bot.getConfiguration();
        LocalDateTime now = LocalDateTime.now();
        
        // Check if within operating hours
        if (!config.isWithinOperatingHours(now.toLocalTime())) {
            return calculateNextOperatingTime(config, now);
        }
        
        // Calculate based on bot type and rate limits
        return calculateNextExecutionBasedOnLimits(bot, config, now);
    }
    
    public boolean canExecuteNow(Bot bot) {
        if (!bot.isActive() || !bot.isReadyToRun()) {
            return false;
        }
        
        BotConfiguration config = bot.getConfiguration();
        LocalTime now = LocalTime.now();
        
        return config.isWithinOperatingHours(now);
    }
    
    public int calculateDelayBetweenActions(BotConfiguration config, int actionsPerformedInHour) {
        int baseDelay = config.delayBetweenActions();
        
        // Increase delay if approaching rate limits
        double usagePercentage = (double) actionsPerformedInHour / config.maxActionsPerHour();
        
        if (usagePercentage > 0.8) { // 80% of limit reached
            return baseDelay * 2; // Double the delay
        } else if (usagePercentage > 0.6) { // 60% of limit reached
            return (int) (baseDelay * 1.5); // 1.5x delay
        }
        
        return baseDelay;
    }
    
    public boolean hasExceededRateLimit(Bot bot, int actionsInLastHour, int actionsToday) {
        BotConfiguration config = bot.getConfiguration();
        
        return actionsInLastHour >= config.maxActionsPerHour() || 
               actionsToday >= config.maxActionsPerDay();
    }
    
    public void validateBotConfiguration(BotType botType, BotConfiguration config) {
        if (botType.requiresTargetAccounts() && config.maxActionsPerHour() == 0) {
            throw new BusinessRuleViolationException(
                "Bot type " + botType + " requires action limits to be configured"
            );
        }
        
        if (botType.isEngagementBot() && config.delayBetweenActions() < 10) {
            throw new BusinessRuleViolationException(
                "Engagement bots must have at least 10 seconds delay between actions"
            );
        }
        
        if (botType == BotType.FOLLOWER && config.maxActionsPerDay() > 500) {
            throw new BusinessRuleViolationException(
                "Follower bots should not exceed 500 actions per day to avoid platform limits"
            );
        }
    }
    
    private LocalDateTime calculateNextOperatingTime(BotConfiguration config, LocalDateTime now) {
        LocalTime startTime = config.startTime();
        if (startTime == null) {
            return now.plusHours(1); // Default to 1 hour later
        }
        
        LocalDateTime nextStart = now.toLocalDate().atTime(startTime);
        
        // If start time has passed today, schedule for tomorrow
        if (nextStart.isBefore(now) || nextStart.equals(now)) {
            nextStart = nextStart.plusDays(1);
        }
        
        return nextStart;
    }
    
    private LocalDateTime calculateNextExecutionBasedOnLimits(Bot bot, BotConfiguration config, LocalDateTime now) {
        // Base delay from configuration
        int delaySeconds = config.delayBetweenActions();
        
        // For continuous bots, use the configured delay
        if (bot.getBotType().canRunContinuously()) {
            return now.plusSeconds(delaySeconds);
        }
        
        // For scheduled bots (like SCHEDULER), calculate based on optimal posting times
        if (bot.getBotType() == BotType.SCHEDULER) {
            return calculateOptimalPostingTime(now);
        }
        
        // For analytics bots, run less frequently
        if (bot.getBotType().isAnalyticsBot()) {
            return now.plusHours(1); // Run every hour
        }
        
        return now.plusSeconds(delaySeconds);
    }
    
    private LocalDateTime calculateOptimalPostingTime(LocalDateTime now) {
        // Simple optimal posting times (can be made more sophisticated)
        int hour = now.getHour();
        
        // Peak engagement times: 9 AM, 1 PM, 6 PM
        int[] peakHours = {9, 13, 18};
        
        for (int peakHour : peakHours) {
            if (hour < peakHour) {
                return now.toLocalDate().atTime(peakHour, 0);
            }
        }
        
        // If past all peak times today, schedule for 9 AM tomorrow
        return now.toLocalDate().plusDays(1).atTime(9, 0);
    }
}
