package com.social.media.domain.campaign.service;

import com.social.media.domain.campaign.aggregate.Campaign;
import com.social.media.domain.campaign.repository.CampaignRepository;
import com.social.media.domain.campaign.valueobject.CampaignId;
import com.social.media.domain.campaign.valueobject.CampaignInteractionStatus;

import com.social.media.domain.user.valueobject.UserId;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * Domain service for Campaign business logic
 */
@Service
public class CampaignDomainService {
    
    private final CampaignRepository campaignRepository;
    
    public CampaignDomainService(CampaignRepository campaignRepository) {
        this.campaignRepository = campaignRepository;
    }
    
    /**
     * Validates if a campaign can be created for the user
     */
    public void validateCampaignCreation(Campaign campaign) {
        // Check if name is unique for the user
        if (campaignRepository.existsByUserIdAndName(campaign.getUserId(), campaign.getName())) {
            throw new BusinessRuleViolationException(
                "A campaign with this name already exists for the user");
        }
        
        // Business rule: User can have maximum 50 active campaigns
        long activeCampaigns = campaignRepository.countByUserIdAndStatus(
            campaign.getUserId(), CampaignInteractionStatus.RUNNING);
        
        if (activeCampaigns >= 50) {
            throw new BusinessRuleViolationException(
                "User has reached the maximum limit of 50 active campaigns");
        }
    }
    
    /**
     * Validates if a campaign can be updated
     */
    public void validateCampaignUpdate(Campaign existingCampaign, String newName) {
        if (!existingCampaign.getName().equals(newName)) {
            // Check if new name is unique for the user
            if (campaignRepository.existsByUserIdAndName(existingCampaign.getUserId(), newName)) {
                throw new BusinessRuleViolationException(
                    "A campaign with this name already exists for the user");
            }
        }
        
        if (!existingCampaign.canBeModified()) {
            throw new BusinessRuleViolationException(
                "Campaign cannot be modified in current status: " + existingCampaign.getStatusInteration());
        }
    }
    
    /**
     * Validates if a campaign can be deleted
     */
    public void validateCampaignDeletion(Campaign campaign) {
        if (campaign.isActive()) {
            throw new BusinessRuleViolationException(
                "Cannot delete an active campaign. Please stop it first.");
        }
    }
    
    /**
     * Gets campaigns that should be automatically started
     */
    public List<Campaign> getCampaignsToAutoStart() {
        LocalDateTime now = LocalDateTime.now();
        return campaignRepository.findCampaignsToStart(now);
    }
    
    /**
     * Gets campaigns that should be automatically stopped
     */
    public List<Campaign> getCampaignsToAutoStop() {
        LocalDateTime now = LocalDateTime.now();
        return campaignRepository.findCampaignsToStop(now);
    }
    
    /**
     * Gets campaign statistics for a user
     */
    public CampaignStatistics getCampaignStatistics(UserId userId) {
        long totalCampaigns = campaignRepository.countByUserId(userId);
        long activeCampaigns = campaignRepository.countByUserIdAndStatus(userId, CampaignInteractionStatus.RUNNING);
        long waitingCampaigns = campaignRepository.countByUserIdAndStatus(userId, CampaignInteractionStatus.WAIT);
        long pausedCampaigns = campaignRepository.countByUserIdAndStatus(userId, CampaignInteractionStatus.PAUSED);
        long completedCampaigns = campaignRepository.countByUserIdAndStatus(userId, CampaignInteractionStatus.COMPLETED);
        long cancelledCampaigns = campaignRepository.countByUserIdAndStatus(userId, CampaignInteractionStatus.CANCELLED);
        
        return new CampaignStatistics(
            totalCampaigns,
            activeCampaigns,
            waitingCampaigns,
            pausedCampaigns,
            completedCampaigns,
            cancelledCampaigns
        );
    }
    
    /**
     * Validates bulk operations
     */
    public void validateBulkStatusChange(List<CampaignId> campaignIds, CampaignInteractionStatus newStatus, UserId userId) {
        for (CampaignId campaignId : campaignIds) {
            Campaign campaign = campaignRepository.findById(campaignId)
                .orElseThrow(() -> new BusinessRuleViolationException("Campaign not found: " + campaignId));
            
            if (!campaign.belongsToUser(userId)) {
                throw new BusinessRuleViolationException("User does not have permission to modify this campaign");
            }
            
            if (!campaign.getStatusInteration().canTransitionTo(newStatus)) {
                throw new BusinessRuleViolationException(
                    String.format("Cannot transition campaign %s from %s to %s", 
                        campaignId, campaign.getStatusInteration(), newStatus));
            }
        }
    }
    
    /**
     * Statistics record for campaign data
     */
    public record CampaignStatistics(
        long totalCampaigns,
        long activeCampaigns,
        long waitingCampaigns,
        long pausedCampaigns,
        long completedCampaigns,
        long cancelledCampaigns
    ) {
        public double getCompletionRate() {
            if (totalCampaigns == 0) return 0.0;
            return (double) completedCampaigns / totalCampaigns * 100;
        }
        
        public double getCancellationRate() {
            if (totalCampaigns == 0) return 0.0;
            return (double) cancelledCampaigns / totalCampaigns * 100;
        }
    }
}
