package com.social.media.domain.automation;

import com.social.media.domain.shared.BaseEntity;
import com.social.media.domain.shared.enums.SocialPlatform;

import java.time.LocalDateTime;
import java.util.UUID;
import java.util.Objects;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;

/**
 * Bot aggregate root representing automation bots for social media activities.
 * Handles automated actions like following, liking, commenting, and posting.
 */
public class Bot extends BaseEntity {
    
    public enum BotType {
        FOLLOWER("Follower Bot", "Automatically follows users based on criteria"),
        UNFOLLOWER("Unfollower Bot", "Automatically unfollows users based on criteria"),
        LIKER("Liker Bot", "Automatically likes posts based on criteria"),
        COMMENTER("Commenter Bot", "Automatically comments on posts"),
        CONTENT_CURATOR("Content Curator", "Automatically shares curated content"),
        ENGAGEMENT("Engagement Bot", "Comprehensive engagement automation"),
        HASHTAG_MONITOR("Hashtag Monitor", "Monitors and engages with hashtag content"),
        COMPETITOR_MONITOR("Competitor Monitor", "Monitors competitor activities"),
        DM_RESPONDER("DM Responder", "Automatically responds to direct messages"),
        SCHEDULER("Scheduler Bot", "Automatically posts scheduled content");
        
        private final String displayName;
        private final String description;
        
        BotType(String displayName, String description) {
            this.displayName = displayName;
            this.description = description;
        }
        
        public String getDisplayName() { return displayName; }
        public String getDescription() { return description; }
    }
    
    public enum BotStatus {
        ACTIVE("Active", "Bot is running and performing actions"),
        PAUSED("Paused", "Bot is temporarily paused"),
        STOPPED("Stopped", "Bot is stopped"),
        ERROR("Error", "Bot encountered an error"),
        RATE_LIMITED("Rate Limited", "Bot is rate limited"),
        SUSPENDED("Suspended", "Bot is suspended due to policy violation"),
        CONFIGURING("Configuring", "Bot is being configured"),
        TESTING("Testing", "Bot is in testing mode");
        
        private final String displayName;
        private final String description;
        
        BotStatus(String displayName, String description) {
            this.displayName = displayName;
            this.description = description;
        }
        
        public String getDisplayName() { return displayName; }
        public String getDescription() { return description; }
    }
    
    private UUID companyId;
    private UUID userId;
    private UUID socialAccountId;
    private String botName;
    private String description;
    private BotType botType;
    private BotStatus status;
    private SocialPlatform platform;
    private boolean isActive;
    private boolean isTestMode;
    
    // Configuration
    private Map<String, Object> configuration;
    private Set<String> targetHashtags;
    private Set<String> targetUsers;
    private Set<String> blacklistedUsers;
    private Set<String> keywords;
    private Set<String> blacklistedKeywords;
    private String targetLocation;
    private Integer minFollowers;
    private Integer maxFollowers;
    private Double engagementRateThreshold;
    
    // Execution settings
    private Integer actionsPerHour;
    private Integer dailyActionLimit;
    private LocalDateTime activeFromTime;
    private LocalDateTime activeToTime;
    private Set<Integer> activeDaysOfWeek; // 1-7, Monday-Sunday
    private Integer delayBetweenActions; // in seconds
    private Integer randomDelayVariation; // in seconds
    
    // Safety settings
    private Integer maxFollowsPerDay;
    private Integer maxLikesPerDay;
    private Integer maxCommentsPerDay;
    private Integer maxUnfollowsPerDay;
    private Integer followRatio; // Max following/followers ratio
    private boolean respectUserPrivacy;
    private boolean avoidBusinessAccounts;
    private boolean avoidVerifiedAccounts;
    
    // Statistics
    private Integer totalActionsPerformed;
    private Integer followsPerformed;
    private Integer unfollowsPerformed;
    private Integer likesPerformed;
    private Integer commentsPerformed;
    private Integer postsShared;
    private Integer dmsSent;
    private LocalDateTime lastActionAt;
    private LocalDateTime lastSuccessfulActionAt;
    private Integer consecutiveErrors;
    private String lastErrorMessage;
    
    // Execution tracking
    private LocalDateTime lastExecutionAt;
    private LocalDateTime nextExecutionAt;
    private String executionStatus;
    private String currentTask;
    private Integer taskProgress;
    private Integer totalTasks;
    
    // Default constructor for JPA
    protected Bot() {
        super();
    }
    
    public Bot(
            UUID companyId,
            UUID userId,
            UUID socialAccountId,
            String botName,
            BotType botType,
            SocialPlatform platform) {
        
        super();
        this.companyId = validateCompanyId(companyId);
        this.userId = validateUserId(userId);
        this.socialAccountId = validateSocialAccountId(socialAccountId);
        this.botName = validateBotName(botName);
        this.botType = validateBotType(botType);
        this.platform = validatePlatform(platform);
        this.status = BotStatus.CONFIGURING;
        this.isActive = false;
        this.isTestMode = true;
        this.configuration = new HashMap<>();
        this.targetHashtags = new HashSet<>();
        this.targetUsers = new HashSet<>();
        this.blacklistedUsers = new HashSet<>();
        this.keywords = new HashSet<>();
        this.blacklistedKeywords = new HashSet<>();
        this.activeDaysOfWeek = new HashSet<>();
        this.totalActionsPerformed = 0;
        this.followsPerformed = 0;
        this.unfollowsPerformed = 0;
        this.likesPerformed = 0;
        this.commentsPerformed = 0;
        this.postsShared = 0;
        this.dmsSent = 0;
        this.consecutiveErrors = 0;
        
        // Default safety settings
        this.actionsPerHour = 30;
        this.dailyActionLimit = 200;
        this.maxFollowsPerDay = 50;
        this.maxLikesPerDay = 100;
        this.maxCommentsPerDay = 20;
        this.maxUnfollowsPerDay = 30;
        this.followRatio = 2;
        this.respectUserPrivacy = true;
        this.avoidBusinessAccounts = false;
        this.avoidVerifiedAccounts = false;
        this.delayBetweenActions = 60;
        this.randomDelayVariation = 30;
    }
    
    // Validation methods
    private UUID validateCompanyId(UUID companyId) {
        if (companyId == null) {
            throw new IllegalArgumentException("Company ID cannot be null");
        }
        return companyId;
    }
    
    private UUID validateUserId(UUID userId) {
        if (userId == null) {
            throw new IllegalArgumentException("User ID cannot be null");
        }
        return userId;
    }
    
    private UUID validateSocialAccountId(UUID socialAccountId) {
        if (socialAccountId == null) {
            throw new IllegalArgumentException("Social Account ID cannot be null");
        }
        return socialAccountId;
    }
    
    private String validateBotName(String botName) {
        if (botName == null || botName.trim().isEmpty()) {
            throw new IllegalArgumentException("Bot name cannot be null or empty");
        }
        if (botName.length() > 100) {
            throw new IllegalArgumentException("Bot name cannot exceed 100 characters");
        }
        return botName.trim();
    }
    
    private BotType validateBotType(BotType botType) {
        if (botType == null) {
            throw new IllegalArgumentException("Bot type cannot be null");
        }
        return botType;
    }
    
    private SocialPlatform validatePlatform(SocialPlatform platform) {
        if (platform == null) {
            throw new IllegalArgumentException("Platform cannot be null");
        }
        return platform;
    }
    
    // Factory methods
    
    /**
     * Creates a follower bot with default settings.
     */
    public static Bot createFollowerBot(
            UUID companyId,
            UUID userId,
            UUID socialAccountId,
            String name,
            SocialPlatform platform) {
        
        Bot bot = new Bot(companyId, userId, socialAccountId, name, BotType.FOLLOWER, platform);
        bot.maxFollowsPerDay = 50;
        bot.actionsPerHour = 20;
        bot.engagementRateThreshold = 2.0;
        return bot;
    }
    
    /**
     * Creates a liker bot with default settings.
     */
    public static Bot createLikerBot(
            UUID companyId,
            UUID userId,
            UUID socialAccountId,
            String name,
            SocialPlatform platform) {
        
        Bot bot = new Bot(companyId, userId, socialAccountId, name, BotType.LIKER, platform);
        bot.maxLikesPerDay = 100;
        bot.actionsPerHour = 30;
        return bot;
    }
    
    /**
     * Creates an engagement bot with balanced settings.
     */
    public static Bot createEngagementBot(
            UUID companyId,
            UUID userId,
            UUID socialAccountId,
            String name,
            SocialPlatform platform) {
        
        Bot bot = new Bot(companyId, userId, socialAccountId, name, BotType.ENGAGEMENT, platform);
        bot.maxFollowsPerDay = 30;
        bot.maxLikesPerDay = 80;
        bot.maxCommentsPerDay = 15;
        bot.actionsPerHour = 25;
        return bot;
    }
    
    // Business methods
    
    /**
     * Activates the bot.
     */
    public void activate() {
        if (status == BotStatus.CONFIGURING) {
            throw new IllegalStateException("Bot must be configured before activation");
        }
        
        this.isActive = true;
        this.status = BotStatus.ACTIVE;
        this.nextExecutionAt = calculateNextExecution();
        this.markAsModified();
    }
    
    /**
     * Pauses the bot.
     */
    public void pause() {
        if (isActive) {
            this.status = BotStatus.PAUSED;
            this.nextExecutionAt = null;
            this.markAsModified();
        }
    }
    
    /**
     * Stops the bot.
     */
    public void stop() {
        this.isActive = false;
        this.status = BotStatus.STOPPED;
        this.nextExecutionAt = null;
        this.currentTask = null;
        this.markAsModified();
    }
    
    /**
     * Updates bot configuration.
     */
    public void updateConfiguration(Map<String, Object> newConfig) {
        if (newConfig != null) {
            this.configuration.clear();
            this.configuration.putAll(newConfig);
            this.markAsModified();
        }
    }
    
    /**
     * Updates targeting criteria.
     */
    public void updateTargeting(
            Set<String> hashtags,
            Set<String> targetUsers,
            Set<String> keywords,
            String location) {
        
        boolean changed = false;
        
        if (hashtags != null && !hashtags.equals(this.targetHashtags)) {
            this.targetHashtags.clear();
            this.targetHashtags.addAll(hashtags);
            changed = true;
        }
        
        if (targetUsers != null && !targetUsers.equals(this.targetUsers)) {
            this.targetUsers.clear();
            this.targetUsers.addAll(targetUsers);
            changed = true;
        }
        
        if (keywords != null && !keywords.equals(this.keywords)) {
            this.keywords.clear();
            this.keywords.addAll(keywords);
            changed = true;
        }
        
        if (!Objects.equals(this.targetLocation, location)) {
            this.targetLocation = location;
            changed = true;
        }
        
        if (changed) {
            this.markAsModified();
        }
    }
    
    /**
     * Updates safety settings.
     */
    public void updateSafetySettings(
            Integer maxFollowsPerDay,
            Integer maxLikesPerDay,
            Integer maxCommentsPerDay,
            Integer actionsPerHour,
            Integer delayBetweenActions) {
        
        boolean changed = false;
        
        if (maxFollowsPerDay != null && maxFollowsPerDay > 0 && !maxFollowsPerDay.equals(this.maxFollowsPerDay)) {
            this.maxFollowsPerDay = maxFollowsPerDay;
            changed = true;
        }
        
        if (maxLikesPerDay != null && maxLikesPerDay > 0 && !maxLikesPerDay.equals(this.maxLikesPerDay)) {
            this.maxLikesPerDay = maxLikesPerDay;
            changed = true;
        }
        
        if (maxCommentsPerDay != null && maxCommentsPerDay > 0 && !maxCommentsPerDay.equals(this.maxCommentsPerDay)) {
            this.maxCommentsPerDay = maxCommentsPerDay;
            changed = true;
        }
        
        if (actionsPerHour != null && actionsPerHour > 0 && !actionsPerHour.equals(this.actionsPerHour)) {
            this.actionsPerHour = actionsPerHour;
            changed = true;
        }
        
        if (delayBetweenActions != null && delayBetweenActions > 0 && !delayBetweenActions.equals(this.delayBetweenActions)) {
            this.delayBetweenActions = delayBetweenActions;
            changed = true;
        }
        
        if (changed) {
            this.markAsModified();
        }
    }
    
    /**
     * Records a successful action.
     */
    public void recordAction(String actionType) {
        this.totalActionsPerformed = (this.totalActionsPerformed != null ? this.totalActionsPerformed : 0) + 1;
        this.lastActionAt = LocalDateTime.now();
        this.lastSuccessfulActionAt = LocalDateTime.now();
        this.consecutiveErrors = 0;
        
        switch (actionType.toLowerCase()) {
            case "follow" -> this.followsPerformed = (this.followsPerformed != null ? this.followsPerformed : 0) + 1;
            case "unfollow" -> this.unfollowsPerformed = (this.unfollowsPerformed != null ? this.unfollowsPerformed : 0) + 1;
            case "like" -> this.likesPerformed = (this.likesPerformed != null ? this.likesPerformed : 0) + 1;
            case "comment" -> this.commentsPerformed = (this.commentsPerformed != null ? this.commentsPerformed : 0) + 1;
            case "share" -> this.postsShared = (this.postsShared != null ? this.postsShared : 0) + 1;
            case "dm" -> this.dmsSent = (this.dmsSent != null ? this.dmsSent : 0) + 1;
        }
        
        this.markAsModified();
    }
    
    /**
     * Records an error.
     */
    public void recordError(String errorMessage) {
        this.consecutiveErrors = (this.consecutiveErrors != null ? this.consecutiveErrors : 0) + 1;
        this.lastErrorMessage = errorMessage;
        this.lastActionAt = LocalDateTime.now();
        
        if (consecutiveErrors >= 5) {
            this.status = BotStatus.ERROR;
            this.isActive = false;
        }
        
        this.markAsModified();
    }
    
    /**
     * Starts execution of a task.
     */
    public void startExecution(String taskName, Integer totalTasks) {
        this.lastExecutionAt = LocalDateTime.now();
        this.executionStatus = "RUNNING";
        this.currentTask = taskName;
        this.taskProgress = 0;
        this.totalTasks = totalTasks;
        this.markAsModified();
    }
    
    /**
     * Updates execution progress.
     */
    public void updateProgress(Integer progress) {
        if (progress != null && progress >= 0) {
            this.taskProgress = progress;
            this.markAsModified();
        }
    }
    
    /**
     * Completes execution.
     */
    public void completeExecution() {
        this.executionStatus = "COMPLETED";
        this.currentTask = null;
        this.taskProgress = null;
        this.totalTasks = null;
        this.nextExecutionAt = calculateNextExecution();
        this.markAsModified();
    }
    
    /**
     * Enables test mode.
     */
    public void enableTestMode() {
        this.isTestMode = true;
        this.markAsModified();
    }
    
    /**
     * Disables test mode.
     */
    public void disableTestMode() {
        this.isTestMode = false;
        this.markAsModified();
    }
    
    /**
     * Marks the bot as rate limited.
     */
    public void markAsRateLimited() {
        this.status = BotStatus.RATE_LIMITED;
        this.nextExecutionAt = LocalDateTime.now().plusHours(1); // Wait 1 hour
        this.markAsModified();
    }
    
    // Helper methods
    
    private LocalDateTime calculateNextExecution() {
        if (!isActive || actionsPerHour == null || actionsPerHour == 0) {
            return null;
        }
        
        int minutesBetweenExecutions = 60 / actionsPerHour;
        return LocalDateTime.now().plusMinutes(minutesBetweenExecutions);
    }
    
    // Query methods
    
    /**
     * Checks if the bot is ready for execution.
     */
    public boolean isReadyForExecution() {
        return isActive &&
               status == BotStatus.ACTIVE &&
               (nextExecutionAt == null || nextExecutionAt.isBefore(LocalDateTime.now()));
    }
    
    /**
     * Checks if the bot has reached daily limits.
     */
    public boolean hasReachedDailyLimits() {
        // This would typically check against today's actions
        // For now, we'll use total actions as an approximation
        return (dailyActionLimit != null && totalActionsPerformed != null && 
                totalActionsPerformed >= dailyActionLimit);
    }
    
    /**
     * Checks if the bot is healthy.
     */
    public boolean isHealthy() {
        return status == BotStatus.ACTIVE &&
               (consecutiveErrors == null || consecutiveErrors < 3);
    }
    
    /**
     * Gets the success rate.
     */
    public Double getSuccessRate() {
        if (totalActionsPerformed == null || totalActionsPerformed == 0) {
            return 100.0;
        }
        
        int errors = consecutiveErrors != null ? consecutiveErrors : 0;
        int successful = totalActionsPerformed - errors;
        return (double) successful / totalActionsPerformed * 100;
    }
    
    /**
     * Gets execution progress percentage.
     */
    public Integer getProgressPercentage() {
        if (taskProgress == null || totalTasks == null || totalTasks == 0) {
            return null;
        }
        return (taskProgress * 100) / totalTasks;
    }
    
    // Getters
    public UUID getCompanyId() { return companyId; }
    public UUID getUserId() { return userId; }
    public UUID getSocialAccountId() { return socialAccountId; }
    public String getBotName() { return botName; }
    public String getDescription() { return description; }
    public BotType getBotType() { return botType; }
    public BotStatus getStatus() { return status; }
    public SocialPlatform getPlatform() { return platform; }
    public boolean isActive() { return isActive; }
    public boolean isTestMode() { return isTestMode; }
    public Map<String, Object> getConfiguration() { return new HashMap<>(configuration); }
    public Set<String> getTargetHashtags() { return new HashSet<>(targetHashtags); }
    public Set<String> getTargetUsers() { return new HashSet<>(targetUsers); }
    public Set<String> getBlacklistedUsers() { return new HashSet<>(blacklistedUsers); }
    public Set<String> getKeywords() { return new HashSet<>(keywords); }
    public Set<String> getBlacklistedKeywords() { return new HashSet<>(blacklistedKeywords); }
    public String getTargetLocation() { return targetLocation; }
    public Integer getMinFollowers() { return minFollowers; }
    public Integer getMaxFollowers() { return maxFollowers; }
    public Double getEngagementRateThreshold() { return engagementRateThreshold; }
    public Integer getActionsPerHour() { return actionsPerHour; }
    public Integer getDailyActionLimit() { return dailyActionLimit; }
    public LocalDateTime getActiveFromTime() { return activeFromTime; }
    public LocalDateTime getActiveToTime() { return activeToTime; }
    public Set<Integer> getActiveDaysOfWeek() { return new HashSet<>(activeDaysOfWeek); }
    public Integer getDelayBetweenActions() { return delayBetweenActions; }
    public Integer getRandomDelayVariation() { return randomDelayVariation; }
    public Integer getMaxFollowsPerDay() { return maxFollowsPerDay; }
    public Integer getMaxLikesPerDay() { return maxLikesPerDay; }
    public Integer getMaxCommentsPerDay() { return maxCommentsPerDay; }
    public Integer getMaxUnfollowsPerDay() { return maxUnfollowsPerDay; }
    public Integer getFollowRatio() { return followRatio; }
    public boolean isRespectUserPrivacy() { return respectUserPrivacy; }
    public boolean isAvoidBusinessAccounts() { return avoidBusinessAccounts; }
    public boolean isAvoidVerifiedAccounts() { return avoidVerifiedAccounts; }
    public Integer getTotalActionsPerformed() { return totalActionsPerformed; }
    public Integer getFollowsPerformed() { return followsPerformed; }
    public Integer getUnfollowsPerformed() { return unfollowsPerformed; }
    public Integer getLikesPerformed() { return likesPerformed; }
    public Integer getCommentsPerformed() { return commentsPerformed; }
    public Integer getPostsShared() { return postsShared; }
    public Integer getDmsSent() { return dmsSent; }
    public LocalDateTime getLastActionAt() { return lastActionAt; }
    public LocalDateTime getLastSuccessfulActionAt() { return lastSuccessfulActionAt; }
    public Integer getConsecutiveErrors() { return consecutiveErrors; }
    public String getLastErrorMessage() { return lastErrorMessage; }
    public LocalDateTime getLastExecutionAt() { return lastExecutionAt; }
    public LocalDateTime getNextExecutionAt() { return nextExecutionAt; }
    public String getExecutionStatus() { return executionStatus; }
    public String getCurrentTask() { return currentTask; }
    public Integer getTaskProgress() { return taskProgress; }
    public Integer getTotalTasks() { return totalTasks; }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
        Bot bot = (Bot) o;
        return Objects.equals(companyId, bot.companyId) &&
               Objects.equals(socialAccountId, bot.socialAccountId) &&
               Objects.equals(botName, bot.botName);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), companyId, socialAccountId, botName);
    }
    
    @Override
    public String toString() {
        return "Bot{" +
               "id=" + getId() +
               ", companyId=" + companyId +
               ", botName='" + botName + '\'' +
               ", botType=" + botType +
               ", status=" + status +
               ", platform=" + platform +
               ", isActive=" + isActive +
               ", totalActionsPerformed=" + totalActionsPerformed +
               '}';
    }
}
