package com.social.media.domain.bot.aggregate;

import com.social.media.domain.bot.valueobject.UserListId;
import com.social.media.domain.company.valueobject.CompanyId;
import com.social.media.domain.user.valueobject.UserId;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import com.social.media.domain.shared.kernel.AggregateRoot;

import java.time.LocalDateTime;
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;

/**
 * UserList aggregate representing lists of target users for bot operations
 */
public class UserList extends AggregateRoot<UserListId> {
    
    private CompanyId companyId;
    private UserId createdBy;
    private String name;
    private String description;
    private Set<String> socialUsernames;
    private Set<String> socialUserIds;
    private boolean isActive;
    private String criteria;
    private int maxUsers;
    private LocalDateTime lastUpdatedAt;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    
    // Constructor for new user list
    public UserList(CompanyId companyId, UserId createdBy, String name, String description) {
        super(UserListId.generate());
        this.companyId = validateCompanyId(companyId);
        this.createdBy = validateCreatedBy(createdBy);
        this.name = validateName(name);
        this.description = description;
        this.socialUsernames = new HashSet<>();
        this.socialUserIds = new HashSet<>();
        this.isActive = true;
        this.maxUsers = 10000; // Default limit
        this.createdAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
        this.lastUpdatedAt = LocalDateTime.now();
    }
    
    // Constructor for existing user list
    public UserList(UserListId id, CompanyId companyId, UserId createdBy, String name, String description,
                    Set<String> socialUsernames, Set<String> socialUserIds, boolean isActive,
                    String criteria, int maxUsers, LocalDateTime lastUpdatedAt,
                    LocalDateTime createdAt, LocalDateTime updatedAt) {
        super(id);
        this.companyId = companyId;
        this.createdBy = createdBy;
        this.name = name;
        this.description = description;
        this.socialUsernames = socialUsernames != null ? new HashSet<>(socialUsernames) : new HashSet<>();
        this.socialUserIds = socialUserIds != null ? new HashSet<>(socialUserIds) : new HashSet<>();
        this.isActive = isActive;
        this.criteria = criteria;
        this.maxUsers = maxUsers;
        this.lastUpdatedAt = lastUpdatedAt;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
    }
    
    // Business methods
    public void updateInfo(String name, String description) {
        this.name = validateName(name);
        this.description = description;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void updateCriteria(String criteria) {
        this.criteria = criteria;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void updateMaxUsers(int maxUsers) {
        if (maxUsers <= 0) {
            throw new BusinessRuleViolationException("Max users must be positive");
        }
        if (maxUsers > 100000) {
            throw new BusinessRuleViolationException("Max users cannot exceed 100,000");
        }
        this.maxUsers = maxUsers;
        
        // If current list exceeds new limit, we should handle this
        if (this.socialUsernames.size() > maxUsers) {
            // This would trigger a business event to handle the excess users
            // For now, we just log the situation
        }
        
        this.updatedAt = LocalDateTime.now();
    }
    
    public void addUser(String username, String userId) {
        if (username == null || username.trim().isEmpty()) {
            throw new BusinessRuleViolationException("Username cannot be empty");
        }
        
        if (this.socialUsernames.size() >= this.maxUsers) {
            throw new BusinessRuleViolationException("User list has reached maximum capacity: " + this.maxUsers);
        }
        
        boolean usernameAdded = this.socialUsernames.add(username.trim().toLowerCase());
        boolean userIdAdded = userId != null ? this.socialUserIds.add(userId.trim()) : false;
        
        if (usernameAdded || userIdAdded) {
            this.lastUpdatedAt = LocalDateTime.now();
            this.updatedAt = LocalDateTime.now();
        }
    }
    
    public void addUsers(List<String> usernames) {
        if (usernames == null || usernames.isEmpty()) {
            return;
        }
        
        int availableSlots = this.maxUsers - this.socialUsernames.size();
        if (usernames.size() > availableSlots) {
            throw new BusinessRuleViolationException(
                String.format("Cannot add %d users. Only %d slots available", usernames.size(), availableSlots)
            );
        }
        
        boolean anyAdded = false;
        for (String username : usernames) {
            if (username != null && !username.trim().isEmpty()) {
                boolean added = this.socialUsernames.add(username.trim().toLowerCase());
                if (added) {
                    anyAdded = true;
                }
            }
        }
        
        if (anyAdded) {
            this.lastUpdatedAt = LocalDateTime.now();
            this.updatedAt = LocalDateTime.now();
        }
    }
    
    public void removeUser(String username) {
        if (username == null || username.trim().isEmpty()) {
            return;
        }
        
        boolean removed = this.socialUsernames.remove(username.trim().toLowerCase());
        if (removed) {
            this.lastUpdatedAt = LocalDateTime.now();
            this.updatedAt = LocalDateTime.now();
        }
    }
    
    public void removeUserById(String userId) {
        if (userId == null || userId.trim().isEmpty()) {
            return;
        }
        
        boolean removed = this.socialUserIds.remove(userId.trim());
        if (removed) {
            this.lastUpdatedAt = LocalDateTime.now();
            this.updatedAt = LocalDateTime.now();
        }
    }
    
    public void removeUsers(List<String> usernames) {
        if (usernames == null || usernames.isEmpty()) {
            return;
        }
        
        boolean anyRemoved = false;
        for (String username : usernames) {
            if (username != null && !username.trim().isEmpty()) {
                boolean removed = this.socialUsernames.remove(username.trim().toLowerCase());
                if (removed) {
                    anyRemoved = true;
                }
            }
        }
        
        if (anyRemoved) {
            this.lastUpdatedAt = LocalDateTime.now();
            this.updatedAt = LocalDateTime.now();
        }
    }
    
    public void clearUsers() {
        if (!this.socialUsernames.isEmpty() || !this.socialUserIds.isEmpty()) {
            this.socialUsernames.clear();
            this.socialUserIds.clear();
            this.lastUpdatedAt = LocalDateTime.now();
            this.updatedAt = LocalDateTime.now();
        }
    }
    
    public void activate() {
        if (this.isActive) {
            throw new BusinessRuleViolationException("User list is already active");
        }
        this.isActive = true;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void deactivate() {
        if (!this.isActive) {
            throw new BusinessRuleViolationException("User list is already inactive");
        }
        this.isActive = false;
        this.updatedAt = LocalDateTime.now();
    }
    
    // Query methods
    public boolean containsUser(String username) {
        if (username == null || username.trim().isEmpty()) {
            return false;
        }
        return this.socialUsernames.contains(username.trim().toLowerCase());
    }
    
    public boolean containsUserId(String userId) {
        if (userId == null || userId.trim().isEmpty()) {
            return false;
        }
        return this.socialUserIds.contains(userId.trim());
    }
    
    public boolean isEmpty() {
        return this.socialUsernames.isEmpty() && this.socialUserIds.isEmpty();
    }
    
    public boolean isFull() {
        return this.socialUsernames.size() >= this.maxUsers;
    }
    
    public int getUserCount() {
        return this.socialUsernames.size();
    }
    
    public int getAvailableSlots() {
        return this.maxUsers - this.socialUsernames.size();
    }
    
    public double getFillPercentage() {
        if (this.maxUsers == 0) {
            return 0.0;
        }
        return (double) this.socialUsernames.size() / this.maxUsers * 100.0;
    }
    
    public boolean belongsToCompany(CompanyId companyId) {
        return this.companyId.equals(companyId);
    }
    
    public boolean wasCreatedBy(UserId userId) {
        return this.createdBy.equals(userId);
    }
    
    public boolean canAddUsers(int count) {
        return this.socialUsernames.size() + count <= this.maxUsers;
    }
    
    public List<String> getUsernamesList() {
        return new ArrayList<>(this.socialUsernames);
    }
    
    public List<String> getUserIdsList() {
        return new ArrayList<>(this.socialUserIds);
    }
    
    public boolean hasRecentActivity(int hours) {
        if (this.lastUpdatedAt == null) {
            return false;
        }
        return this.lastUpdatedAt.isAfter(LocalDateTime.now().minusHours(hours));
    }
    
    // Validation methods
    private CompanyId validateCompanyId(CompanyId companyId) {
        if (companyId == null) {
            throw new BusinessRuleViolationException("Company ID is required");
        }
        return companyId;
    }
    
    private UserId validateCreatedBy(UserId createdBy) {
        if (createdBy == null) {
            throw new BusinessRuleViolationException("Created by user ID is required");
        }
        return createdBy;
    }
    
    private String validateName(String name) {
        if (name == null || name.trim().isEmpty()) {
            throw new BusinessRuleViolationException("User list name is required");
        }
        if (name.length() > 100) {
            throw new BusinessRuleViolationException("User list name must not exceed 100 characters");
        }
        return name.trim();
    }
    
    // Getters
    public CompanyId getCompanyId() { return companyId; }
    public UserId getCreatedBy() { return createdBy; }
    public String getName() { return name; }
    public String getDescription() { return description; }
    public Set<String> getSocialUsernames() { return new HashSet<>(socialUsernames); }
    public Set<String> getSocialUserIds() { return new HashSet<>(socialUserIds); }
    public boolean isActive() { return isActive; }
    public String getCriteria() { return criteria; }
    public int getMaxUsers() { return maxUsers; }
    public LocalDateTime getLastUpdatedAt() { return lastUpdatedAt; }
    public LocalDateTime getCreatedAt() { return createdAt; }
    public LocalDateTime getUpdatedAt() { return updatedAt; }
}
