package com.social.media.domain.campaign.service;

import com.social.media.domain.campaign.aggregate.AutomationCampaign;
import com.social.media.domain.campaign.entity.CampaignExecution;
import com.social.media.domain.campaign.repository.AutomationCampaignRepository;
import com.social.media.domain.campaign.valueobject.*;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * Domain Service for Automation Campaign business logic
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AutomationCampaignDomainService {
    
    private final AutomationCampaignRepository campaignRepository;
    
    /**
     * Create a new automation campaign
     */
    public AutomationCampaign createCampaign(Long companyId, Long socialAccountId, String name, 
                                           String description, CampaignType type,
                                           TargetConfiguration targetConfig,
                                           ActionConfiguration actionConfig,
                                           ScheduleConfiguration scheduleConfig) {
        
        // Validate business rules
        validateCampaignName(companyId, name);
        validateConfigurations(targetConfig, actionConfig, scheduleConfig);
        
        // Generate unique campaign code
        String campaignCode = generateUniqueCampaignCode();
        
        // Create campaign
        AutomationCampaign campaign = AutomationCampaign.builder()
                .campaignCode(campaignCode)
                .companyId(companyId)
                .socialAccountId(socialAccountId)
                .name(name)
                .description(description)
                .type(type)
                .status(CampaignStatus.DRAFT)
                .targetConfig(targetConfig)
                .actionConfig(actionConfig)
                .scheduleConfig(scheduleConfig)
                .totalPlannedActions(0)
                .totalExecutedActions(0)
                .successfulActions(0)
                .failedActions(0)
                .isActive(true)
                .autoRestart(false)
                .createdAt(LocalDateTime.now())
                .updatedAt(LocalDateTime.now())
                .build();
        
        return campaignRepository.save(campaign);
    }
    
    /**
     * Validate campaign configurations
     */
    public void validateConfigurations(TargetConfiguration targetConfig,
                                     ActionConfiguration actionConfig,
                                     ScheduleConfiguration scheduleConfig) {
        
        if (targetConfig == null) {
            throw new BusinessRuleViolationException("Target configuration is required");
        }
        
        if (actionConfig == null) {
            throw new BusinessRuleViolationException("Action configuration is required");
        }
        
        if (scheduleConfig == null) {
            throw new BusinessRuleViolationException("Schedule configuration is required");
        }
        
        // Validate at least one target is defined
        if (!targetConfig.hasTargetUsers() && !targetConfig.hasTargetHashtags() && !targetConfig.hasTargetLocations()) {
            throw new BusinessRuleViolationException("At least one target criteria must be defined");
        }
        
        // Validate actions are defined
        if (actionConfig.getAllowedActions() == null || actionConfig.getAllowedActions().isEmpty()) {
            throw new BusinessRuleViolationException("At least one action must be defined");
        }
        
        // Validate schedule dates
        if (scheduleConfig.getStartDate() != null && scheduleConfig.getEndDate() != null) {
            if (scheduleConfig.getEndDate().isBefore(scheduleConfig.getStartDate())) {
                throw new BusinessRuleViolationException("End date must be after start date");
            }
        }
    }
    
    /**
     * Create campaign execution
     */
    public CampaignExecution createExecution(Long campaignId, ActionType actionType,
                                           String targetUserId, String targetPostId) {
        
        String executionCode = generateUniqueExecutionCode();
        
        return CampaignExecution.builder()
                .executionCode(executionCode)
                .campaignId(campaignId)
                .actionType(actionType)
                .status(ExecutionStatus.PENDING)
                .targetUserId(targetUserId)
                .targetPostId(targetPostId)
                .plannedExecutionDate(LocalDateTime.now())
                .retryCount(0)
                .maxRetries(3)
                .createdAt(LocalDateTime.now())
                .build();
    }
    
    /**
     * Check if campaign can be executed now
     */
    public boolean canExecuteNow(AutomationCampaign campaign) {
        if (!campaign.isActive()) {
            return false;
        }
        
        ScheduleConfiguration scheduleConfig = campaign.getScheduleConfig();
        if (scheduleConfig == null) {
            return true;
        }
        
        return scheduleConfig.isWithinSchedulePeriod() && scheduleConfig.isWithinWorkingHours();
    }
    
    /**
     * Validate rate limits
     */
    public boolean validateRateLimits(AutomationCampaign campaign, int plannedActions) {
        ScheduleConfiguration scheduleConfig = campaign.getScheduleConfig();
        if (scheduleConfig == null) {
            return true;
        }
        
        // Check daily limit
        if (scheduleConfig.getDailyLimit() != null) {
            // In a real implementation, we would check actions executed today
            return plannedActions <= scheduleConfig.getDailyLimit();
        }
        
        return true;
    }
    
    private void validateCampaignName(Long companyId, String name) {
        if (campaignRepository.existsByCompanyIdAndName(companyId, name)) {
            throw new BusinessRuleViolationException("Campaign name already exists for this company");
        }
    }
    
    private String generateUniqueCampaignCode() {
        String code;
        do {
            code = "CAM-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
        } while (campaignRepository.existsByCampaignCode(code));
        
        return code;
    }
    
    private String generateUniqueExecutionCode() {
        return "EXE-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
    }
}
