package com.social.media.domain.campaign.aggregate;

import com.social.media.domain.campaign.valueobject.*;
import com.social.media.domain.shared.AggregateRoot;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import com.social.media.domain.shared.exception.DomainException;
import lombok.Getter;
import lombok.experimental.SuperBuilder;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * Automation Campaign Aggregate Root
 * Represents a modern automation campaign with advanced configuration
 * Based on the new campaigns table structure
 */
@Getter
@SuperBuilder
public class AutomationCampaign extends AggregateRoot<AutomationCampaignId> {
    
    private final String campaignCode;
    private final Long companyId;
    private final Long socialAccountId;
    
    // Campaign information
    private String name;
    private String description;
    private CampaignType campaignType;
    private CampaignStatus status;
    
    // Configuration (JSON stored as value objects)
    private TargetConfiguration targetConfig;
    private ActionConfiguration actionConfig;
    private ScheduleConfiguration scheduleConfig;
    
    // Execution tracking
    private Integer totalPlannedActions;
    private Integer totalExecutedActions;
    private Integer successfulActions;
    private Integer failedActions;
    
    // Dates
    private LocalDateTime plannedStartDate;
    private LocalDateTime plannedEndDate;
    private LocalDateTime actualStartDate;
    private LocalDateTime actualEndDate;
    private LocalDateTime lastExecutionDate;
    
    // Flags
    private Boolean isActive;
    private Boolean autoRestart;
    
    // Business Rules
    public void validateCampaignDates() {
        if (plannedEndDate != null && plannedStartDate != null && 
            plannedEndDate.isBefore(plannedStartDate)) {
            throw new BusinessRuleViolationException("Campaign end date cannot be before start date");
        }
    }
    
    public void validateExecutionStatistics() {
        if (totalExecutedActions < 0 || successfulActions < 0 || failedActions < 0) {
            throw new BusinessRuleViolationException("Execution statistics cannot be negative");
        }
        
        if (totalExecutedActions > totalPlannedActions) {
            throw new BusinessRuleViolationException("Executed actions cannot exceed planned actions");
        }
        
        if (successfulActions + failedActions > totalExecutedActions) {
            throw new BusinessRuleViolationException("Sum of successful and failed actions cannot exceed total executed");
        }
    }
    
    public void start() {
        if (status != CampaignStatus.DRAFT && status != CampaignStatus.PAUSED) {
            throw new DomainException("Campaign can only be started from DRAFT or PAUSED status");
        }
        
        if (!isActive) {
            throw new DomainException("Cannot start inactive campaign");
        }
        
        this.status = CampaignStatus.ACTIVE;
        this.actualStartDate = LocalDateTime.now();
        
        publishDomainEvent(new CampaignStartedEvent(getId(), name, actualStartDate));
    }
    
    public void pause() {
        if (status != CampaignStatus.ACTIVE) {
            throw new DomainException("Only active campaigns can be paused");
        }
        
        this.status = CampaignStatus.PAUSED;
        publishDomainEvent(new CampaignPausedEvent(getId(), name, LocalDateTime.now()));
    }
    
    public void complete() {
        if (status != CampaignStatus.ACTIVE) {
            throw new DomainException("Only active campaigns can be completed");
        }
        
        this.status = CampaignStatus.COMPLETED;
        this.actualEndDate = LocalDateTime.now();
        publishDomainEvent(new CampaignCompletedEvent(getId(), name, actualEndDate));
    }
    
    public void cancel() {
        if (status == CampaignStatus.COMPLETED || status == CampaignStatus.CANCELLED) {
            throw new DomainException("Cannot cancel completed or already cancelled campaign");
        }
        
        this.status = CampaignStatus.CANCELLED;
        this.actualEndDate = LocalDateTime.now();
        publishDomainEvent(new CampaignCancelledEvent(getId(), name, actualEndDate));
    }
    
    public void updateExecutionMetrics(Integer executed, Integer successful, Integer failed) {
        this.totalExecutedActions = executed;
        this.successfulActions = successful;
        this.failedActions = failed;
        this.lastExecutionDate = LocalDateTime.now();
        
        validateExecutionStatistics();
        
        // Check if campaign should be completed
        if (totalExecutedActions.equals(totalPlannedActions) && status == CampaignStatus.ACTIVE) {
            complete();
        }
    }
    
    public void updateConfiguration(TargetConfiguration targetConfig, 
                                   ActionConfiguration actionConfig, 
                                   ScheduleConfiguration scheduleConfig) {
        if (status == CampaignStatus.ACTIVE) {
            throw new DomainException("Cannot update configuration of active campaign");
        }
        
        this.targetConfig = targetConfig;
        this.actionConfig = actionConfig;
        this.scheduleConfig = scheduleConfig;
        
        publishDomainEvent(new CampaignConfigurationUpdatedEvent(getId(), name));
    }
    
    // Helper methods
    public Double getSuccessRate() {
        if (totalExecutedActions == null || totalExecutedActions == 0) {
            return 0.0;
        }
        return (successfulActions.doubleValue() / totalExecutedActions.doubleValue()) * 100.0;
    }
    
    public Boolean isCompleted() {
        return status == CampaignStatus.COMPLETED;
    }
    
    public Boolean isActiveStatus() {
        return status == CampaignStatus.ACTIVE;
    }
    
    // Domain Events
    public record CampaignStartedEvent(AutomationCampaignId campaignId, String campaignName, LocalDateTime startedAt) {}
    public record CampaignPausedEvent(AutomationCampaignId campaignId, String campaignName, LocalDateTime pausedAt) {}
    public record CampaignCompletedEvent(AutomationCampaignId campaignId, String campaignName, LocalDateTime completedAt) {}
    public record CampaignCancelledEvent(AutomationCampaignId campaignId, String campaignName, LocalDateTime cancelledAt) {}
    public record CampaignConfigurationUpdatedEvent(AutomationCampaignId campaignId, String campaignName) {}
}
