package com.social.media.domain.campaign.entity;

import com.social.media.domain.campaign.valueobject.*;
import com.social.media.domain.shared.BaseEntity;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import lombok.Getter;
import lombok.experimental.SuperBuilder;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * Campaign Execution Entity
 * Represents individual execution of campaign actions
 */
@Getter
@SuperBuilder
public class CampaignExecution extends BaseEntity<CampaignExecutionId> {
    
    private final String executionCode;
    private final AutomationCampaignId campaignId;
    private final Long socialAccountId;
    
    // Target information
    private String targetUsername;
    private String targetPostId;
    private String targetUserId;
    
    // Action details
    private ActionType actionType;
    private String actionText;
    private Map<String, Object> actionParameters;
    
    // Execution status and timing
    private ExecutionStatus status;
    private LocalDateTime executionTime;
    private LocalDateTime completionTime;
    private Integer durationSeconds;
    
    // Error handling
    private String errorMessage;
    private String errorCode;
    private Integer retryCount;
    private Integer maxRetries;
    
    // API Response data
    private Map<String, Object> responseData;
    private Integer apiResponseCode;
    private String apiResponseMessage;
    
    // Metrics
    private EngagementResult engagementResult;
    
    // Rate limiting tracking
    private Boolean rateLimitHit;
    private LocalDateTime rateLimitResetTime;
    
    @Getter
    @SuperBuilder
    public static class EngagementResult {
        private Integer likes;
        private Integer comments;
        private Integer shares;
        private Integer saves;
        private Integer views;
        
        public static EngagementResult empty() {
            return EngagementResult.builder()
                .likes(0)
                .comments(0)
                .shares(0)
                .saves(0)
                .views(0)
                .build();
        }
    }
    
    // Business methods
    public void execute() {
        if (status != ExecutionStatus.PENDING) {
            throw new BusinessRuleViolationException("Can only execute pending executions");
        }
        
        this.status = ExecutionStatus.RUNNING;
        this.executionTime = LocalDateTime.now();
    }
    
    public void complete(Map<String, Object> responseData, EngagementResult result) {
        if (status != ExecutionStatus.RUNNING) {
            throw new BusinessRuleViolationException("Can only complete running executions");
        }
        
        this.status = ExecutionStatus.COMPLETED;
        this.completionTime = LocalDateTime.now();
        this.responseData = responseData;
        this.engagementResult = result;
        
        if (executionTime != null) {
            this.durationSeconds = (int) java.time.Duration.between(executionTime, completionTime).getSeconds();
        }
    }
    
    public void fail(String errorMessage, String errorCode, Map<String, Object> responseData) {
        this.status = ExecutionStatus.FAILED;
        this.completionTime = LocalDateTime.now();
        this.errorMessage = errorMessage;
        this.errorCode = errorCode;
        this.responseData = responseData;
        
        if (executionTime != null) {
            this.durationSeconds = (int) java.time.Duration.between(executionTime, completionTime).getSeconds();
        }
    }
    
    public void cancel() {
        if (status.isFinished()) {
            throw new BusinessRuleViolationException("Cannot cancel finished execution");
        }
        
        this.status = ExecutionStatus.CANCELLED;
        this.completionTime = LocalDateTime.now();
        
        if (executionTime != null) {
            this.durationSeconds = (int) java.time.Duration.between(executionTime, completionTime).getSeconds();
        }
    }
    
    public boolean canRetry() {
        return status == ExecutionStatus.FAILED && retryCount < maxRetries;
    }
    
    public void retry() {
        if (!canRetry()) {
            throw new BusinessRuleViolationException("Cannot retry this execution");
        }
        
        this.retryCount++;
        this.status = ExecutionStatus.PENDING;
        this.errorMessage = null;
        this.errorCode = null;
        this.completionTime = null;
        this.durationSeconds = null;
    }
    
    public void hitRateLimit(LocalDateTime resetTime) {
        this.rateLimitHit = true;
        this.rateLimitResetTime = resetTime;
        
        if (status == ExecutionStatus.RUNNING) {
            fail("Rate limit exceeded", "RATE_LIMIT", Map.of("resetTime", resetTime));
        }
    }
    
    public boolean isSuccessful() {
        return status == ExecutionStatus.COMPLETED;
    }
    
    public boolean isFailed() {
        return status == ExecutionStatus.FAILED;
    }
    
    public boolean isFinished() {
        return status.isFinished();
    }
}
