package com.social.media.domain.user.service;

import com.social.media.domain.user.aggregate.User;
import com.social.media.domain.user.repository.UserRepository;
import com.social.media.domain.shared.enums.UserType;
import com.social.media.domain.company.valueobject.CompanyId;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import org.springframework.stereotype.Service;

/**
 * Domain service for User business rules and validations
 * Encapsulates complex business logic that doesn't naturally fit within a single aggregate
 */
@Service
public class UserDomainService {
    
    private final UserRepository userRepository;
    
    public UserDomainService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    /**
     * Validates if a user can be created with the specified type
     * 
     * Rule 1: Only one SUPER_ADMIN can exist in the system
     * Rule 2: ADMIN users can only manage users within their own company
     */
    public void validateUserCreation(UserType userType, CompanyId companyId, User createdBy) {
        // Rule 1: Only one SUPER_ADMIN can exist
        if (userType == UserType.SUPER_ADMIN) {
            if (userRepository.existsSuperAdmin()) {
                throw new BusinessRuleViolationException(
                    "Only one SUPER_ADMIN user can exist in the system");
            }
            
            // Only existing SUPER_ADMIN can create another SUPER_ADMIN (for system migration scenarios)
            if (createdBy != null && !createdBy.getType().isSuperAdmin()) {
                throw new BusinessRuleViolationException(
                    "Only SUPER_ADMIN can create another SUPER_ADMIN user");
            }
        }
        
        // Rule 2: ADMIN users restrictions
        if (createdBy != null && createdBy.getType().isRegularAdmin()) {
            validateAdminUserCreation(userType, companyId, createdBy);
        }
    }
    
    /**
     * Validates user update operations
     */
    public void validateUserUpdate(User userToUpdate, UserType newUserType, User updatedBy) {
        // Prevent changing SUPER_ADMIN type
        if (userToUpdate.getType().isSuperAdmin() && newUserType != UserType.SUPER_ADMIN) {
            throw new BusinessRuleViolationException(
                "SUPER_ADMIN user type cannot be changed");
        }
        
        // Prevent creating SUPER_ADMIN through update
        if (!userToUpdate.getType().isSuperAdmin() && newUserType == UserType.SUPER_ADMIN) {
            throw new BusinessRuleViolationException(
                "Users cannot be promoted to SUPER_ADMIN through update");
        }
        
        // ADMIN users restrictions for updates
        if (updatedBy != null && updatedBy.getType().isRegularAdmin()) {
            validateAdminUserUpdate(userToUpdate, newUserType, updatedBy);
        }
    }
    
    /**
     * Validates if a user can delete another user
     */
    public void validateUserDeletion(User userToDelete, User deletedBy) {
        // Cannot delete SUPER_ADMIN
        if (userToDelete.getType().isSuperAdmin()) {
            throw new BusinessRuleViolationException(
                "SUPER_ADMIN user cannot be deleted");
        }
        
        // ADMIN users can only delete users from their own company
        if (deletedBy != null && deletedBy.getType().isRegularAdmin()) {
            if (!userToDelete.getCompanyId().equals(deletedBy.getCompanyId())) {
                throw new BusinessRuleViolationException(
                    "ADMIN users can only delete users from their own company");
            }
        }
    }
    
    /**
     * Validates if an admin user can manage companies
     */
    public void validateCompanyManagement(User user) {
        if (user.getType().isRegularAdmin()) {
            throw new BusinessRuleViolationException(
                "ADMIN users cannot create, edit or delete companies");
        }
    }
    
    /**
     * Private method to validate ADMIN user creation rules
     */
    private void validateAdminUserCreation(UserType userType, CompanyId companyId, User createdBy) {
        // ADMIN cannot create SUPER_ADMIN
        if (userType == UserType.SUPER_ADMIN) {
            throw new BusinessRuleViolationException(
                "ADMIN users cannot create SUPER_ADMIN users");
        }
        
        // ADMIN can only create users in their own company
        if (!companyId.equals(createdBy.getCompanyId())) {
            throw new BusinessRuleViolationException(
                "ADMIN users can only create users in their own company");
        }
        
        // ADMIN cannot create other ADMIN users
        if (userType == UserType.ADMIN) {
            throw new BusinessRuleViolationException(
                "ADMIN users cannot create other ADMIN users");
        }
    }
    
    /**
     * Private method to validate ADMIN user update rules
     */
    private void validateAdminUserUpdate(User userToUpdate, UserType newUserType, User updatedBy) {
        // ADMIN can only update users from their own company
        if (!userToUpdate.getCompanyId().equals(updatedBy.getCompanyId())) {
            throw new BusinessRuleViolationException(
                "ADMIN users can only update users from their own company");
        }
        
        // ADMIN cannot promote users to ADMIN
        if (newUserType == UserType.ADMIN && !userToUpdate.getType().isRegularAdmin()) {
            throw new BusinessRuleViolationException(
                "ADMIN users cannot promote other users to ADMIN");
        }
        
        // ADMIN cannot update other ADMIN users (unless it's themselves)
        if (userToUpdate.getType().isRegularAdmin() && 
            !userToUpdate.getId().equals(updatedBy.getId())) {
            throw new BusinessRuleViolationException(
                "ADMIN users cannot update other ADMIN users");
        }
    }
    
    /**
     * Checks if a user can access another user's data
     */
    public boolean canAccessUser(User accessor, User target) {
        // SUPER_ADMIN can access anyone
        if (accessor.getType().isSuperAdmin()) {
            return true;
        }
        
        // ADMIN can access users from their own company
        if (accessor.getType().isRegularAdmin()) {
            return accessor.getCompanyId().equals(target.getCompanyId());
        }
        
        // Other users can only access themselves
        return accessor.getId().equals(target.getId());
    }
    
    /**
     * Gets the maximum user type an admin can create
     */
    public UserType getMaximumCreatableUserType(User creator) {
        if (creator.getType().isSuperAdmin()) {
            return UserType.ADMIN; // SUPER_ADMIN can create up to ADMIN
        }
        
        if (creator.getType().isRegularAdmin()) {
            return UserType.MANAGER; // ADMIN can create up to MANAGER
        }
        
        if (creator.getType() == UserType.MANAGER) {
            return UserType.USER; // MANAGER can create up to USER
        }
        
        return UserType.VIEWER; // Default for others
    }
}
