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.repository.CampaignExecutionRepository;
import com.social.media.domain.campaign.valueobject.*;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import com.social.media.domain.shared.exception.DomainException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * Campaign Domain Service
 * Implements complex business logic for campaign management
 */
@Service
@RequiredArgsConstructor
public class AutomationCampaignDomainService {
    
    private final AutomationCampaignRepository campaignRepository;
    private final CampaignExecutionRepository executionRepository;
    
    /**
     * Creates a new automation campaign with validation
     */
    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 campaign code
        String campaignCode = generateCampaignCode();
        
        // Create campaign
        AutomationCampaign campaign = AutomationCampaign.builder()
                .id(AutomationCampaignId.generate())
                .campaignCode(campaignCode)
                .companyId(companyId)
                .socialAccountId(socialAccountId)
                .name(name)
                .description(description)
                .campaignType(type)
                .status(CampaignStatus.DRAFT)
                .targetConfig(targetConfig)
                .actionConfig(actionConfig)
                .scheduleConfig(scheduleConfig)
                .totalPlannedActions(0)
                .totalExecutedActions(0)
                .successfulActions(0)
                .failedActions(0)
                .isActive(true)
                .autoRestart(false)
                .build();
        
        return campaignRepository.save(campaign);
    }
    
    /**
     * Updates campaign configuration
     */
    public AutomationCampaign updateCampaignConfiguration(
            AutomationCampaignId campaignId,
            TargetConfiguration targetConfig,
            ActionConfiguration actionConfig,
            ScheduleConfiguration scheduleConfig) {
        
        AutomationCampaign campaign = getCampaignById(campaignId);
        validateConfigurations(targetConfig, actionConfig, scheduleConfig);
        
        campaign.updateConfiguration(targetConfig, actionConfig, scheduleConfig);
        
        return campaignRepository.save(campaign);
    }
    
    /**
     * Starts a campaign
     */
    public AutomationCampaign startCampaign(AutomationCampaignId campaignId) {
        AutomationCampaign campaign = getCampaignById(campaignId);
        
        // Validate campaign can be started
        validateCampaignCanStart(campaign);
        
        campaign.start();
        
        return campaignRepository.save(campaign);
    }
    
    /**
     * Pauses a campaign
     */
    public AutomationCampaign pauseCampaign(AutomationCampaignId campaignId) {
        AutomationCampaign campaign = getCampaignById(campaignId);
        campaign.pause();
        
        return campaignRepository.save(campaign);
    }
    
    /**
     * Completes a campaign
     */
    public AutomationCampaign completeCampaign(AutomationCampaignId campaignId) {
        AutomationCampaign campaign = getCampaignById(campaignId);
        campaign.complete();
        
        return campaignRepository.save(campaign);
    }
    
    /**
     * Cancels a campaign
     */
    public AutomationCampaign cancelCampaign(AutomationCampaignId campaignId) {
        AutomationCampaign campaign = getCampaignById(campaignId);
        campaign.cancel();
        
        return campaignRepository.save(campaign);
    }
    
    /**
     * Creates a campaign execution
     */
    public CampaignExecution createExecution(
            AutomationCampaignId campaignId,
            Long socialAccountId,
            ActionType actionType,
            String targetUsername,
            String targetPostId,
            String actionText,
            Map<String, Object> actionParameters) {
        
        // Validate campaign exists and is active
        AutomationCampaign campaign = getCampaignById(campaignId);
        if (!campaign.isActiveStatus()) {
            throw new DomainException("Cannot create execution for inactive campaign");
        }
        
        // Generate execution code
        String executionCode = generateExecutionCode();
        
        // Create execution
        CampaignExecution execution = CampaignExecution.builder()
                .id(CampaignExecutionId.generate())
                .executionCode(executionCode)
                .campaignId(campaignId)
                .socialAccountId(socialAccountId)
                .targetUsername(targetUsername)
                .targetPostId(targetPostId)
                .actionType(actionType)
                .actionText(actionText)
                .actionParameters(actionParameters)
                .status(ExecutionStatus.PENDING)
                .retryCount(0)
                .maxRetries(3)
                .rateLimitHit(false)
                .engagementResult(CampaignExecution.EngagementResult.empty())
                .build();
        
        return executionRepository.save(execution);
    }
    
    /**
     * Updates campaign execution metrics
     */
    public AutomationCampaign updateCampaignMetrics(AutomationCampaignId campaignId) {
        AutomationCampaign campaign = getCampaignById(campaignId);
        
        // Calculate metrics from executions
        List<CampaignExecution> executions = executionRepository.findByCampaignId(campaignId);
        
        int totalExecuted = executions.size();
        int successful = (int) executions.stream()
                .filter(CampaignExecution::isSuccessful)
                .count();
        int failed = (int) executions.stream()
                .filter(CampaignExecution::isFailed)
                .count();
        
        campaign.updateExecutionMetrics(totalExecuted, successful, failed);
        
        return campaignRepository.save(campaign);
    }
    
    /**
     * Finds campaigns ready for execution
     */
    public List<AutomationCampaign> findCampaignsForExecution() {
        LocalDateTime now = LocalDateTime.now();
        return campaignRepository.findCampaignsForExecution(now);
    }
    
    // Helper methods
    private AutomationCampaign getCampaignById(AutomationCampaignId campaignId) {
        return campaignRepository.findById(campaignId)
                .orElseThrow(() -> new DomainException("Campaign not found: " + campaignId.getValue()));
    }
    
    private void validateCampaignName(Long companyId, String name) {
        if (campaignRepository.findByCompanyIdAndName(companyId, name).isPresent()) {
            throw new BusinessRuleViolationException("Campaign name already exists for this company");
        }
    }
    
    private void validateConfigurations(TargetConfiguration targetConfig, 
                                       ActionConfiguration actionConfig, 
                                       ScheduleConfiguration scheduleConfig) {
        // Validate target configuration
        if (!targetConfig.hasTargetUsers() && !targetConfig.hasTargetHashtags() && !targetConfig.hasTargetLocations()) {
            throw new BusinessRuleViolationException("Campaign must have at least one target");
        }
        
        // Validate action configuration
        if (!actionConfig.hasActions()) {
            throw new BusinessRuleViolationException("Campaign must have at least one action");
        }
        
        if (actionConfig.requiresTextTemplates() && !actionConfig.hasCommentTemplates() && !actionConfig.hasDmTemplates()) {
            throw new BusinessRuleViolationException("Campaign with comment/DM actions must have text templates");
        }
        
        // Validate schedule configuration
        if (scheduleConfig.hasDateRange() && scheduleConfig.getEndDate().isBefore(scheduleConfig.getStartDate())) {
            throw new BusinessRuleViolationException("Campaign end date cannot be before start date");
        }
    }
    
    private void validateCampaignCanStart(AutomationCampaign campaign) {
        // Check if schedule is configured
        if (campaign.getScheduleConfig() == null) {
            throw new BusinessRuleViolationException("Campaign must have schedule configuration to start");
        }
        
        // Check if actions are configured
        if (campaign.getActionConfig() == null || !campaign.getActionConfig().hasActions()) {
            throw new BusinessRuleViolationException("Campaign must have actions configured to start");
        }
        
        // Check if targets are configured
        if (campaign.getTargetConfig() == null) {
            throw new BusinessRuleViolationException("Campaign must have targets configured to start");
        }
    }
    
    private String generateCampaignCode() {
        return "CAM" + String.format("%06d", System.currentTimeMillis() % 1000000);
    }
    
    private String generateExecutionCode() {
        return "CEXE" + String.format("%08d", System.currentTimeMillis() % 100000000);
    }
}
