package com.social.media.application.user.handler;

import com.social.media.application.user.command.UpdateUserCommand;
import com.social.media.application.user.dto.UserResponseDto;
import com.social.media.domain.user.aggregate.User;
import com.social.media.domain.user.repository.UserRepository;
import com.social.media.domain.user.service.UserDomainService;
import com.social.media.domain.shared.valueobject.Phone;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;

@Service
public class UpdateUserCommandHandler {
    
    private final UserRepository userRepository;
    private final UserDomainService userDomainService;
    
    public UpdateUserCommandHandler(UserRepository userRepository, UserDomainService userDomainService) {
        this.userRepository = userRepository;
        this.userDomainService = userDomainService;
    }
    
    @Transactional
    public UserResponseDto handle(UpdateUserCommand command) {
        User user = userRepository.findById(command.userId())
            .orElseThrow(() -> new BusinessRuleViolationException("User not found with ID: " + command.userId()));
        
        // Get updater user for validation
        User updatedBy = null;
        if (command.updatedBy() != null) {
            updatedBy = userRepository.findById(command.updatedBy())
                .orElseThrow(() -> new BusinessRuleViolationException("Updater user not found"));
        }
        
        // Validate user type changes using domain service
        if (command.userType() != null && !command.userType().equals(user.getType())) {
            userDomainService.validateUserUpdate(user, command.userType(), updatedBy);
            // Note: User type update would require a more complex business method on User aggregate
            // For now, this validation ensures the business rules are checked
        }
        
        // Update profile information
        if (command.name() != null || command.phone() != null || 
            command.position() != null || command.department() != null) {
            
            String name = command.name() != null ? command.name() : user.getName();
            Phone phone = command.phone() != null ? new Phone(command.phone()) : user.getPhone();
            String position = command.position() != null ? command.position() : user.getPosition();
            String department = command.department() != null ? command.department() : user.getDepartment();
            
            user.updateProfile(name, phone, position, department);
        }
        
        if (command.avatarUrl() != null) {
            user.setAvatar(command.avatarUrl());
        }
        
        if (command.whatsappEnabled() != null && command.whatsappEnabled()) {
            user.enableWhatsapp();
        } else if (command.whatsappEnabled() != null && !command.whatsappEnabled()) {
            user.disableWhatsapp();
        }
        
        User updatedUser = userRepository.save(user);
        
        return UserResponseDto.builder()
            .id(updatedUser.getId().value().toString())
            .name(updatedUser.getName())
            .email(updatedUser.getEmail().value())
            .phone(updatedUser.getPhone() != null ? updatedUser.getPhone().value() : null)
            .position(updatedUser.getPosition())
            .department(updatedUser.getDepartment())
            .status(updatedUser.getStatus().name())
            .companyId(updatedUser.getCompanyId().value().toString())
            .avatarUrl(updatedUser.getAvatarUrl())
            .emailVerified(updatedUser.isEmailVerified())
            .whatsappEnabled(updatedUser.isWhatsappEnabled())
            .lastAccessDate(updatedUser.getLastAccessDate())
            .permissions(updatedUser.getPermissions().permissions())
            .configuration(Map.of(
                "timezone", updatedUser.getConfiguration().timezone(),
                "language", updatedUser.getConfiguration().language(),
                "preferences", updatedUser.getConfiguration().preferences()
            ))
            .createdAt(updatedUser.getCreatedAt())
            .updatedAt(updatedUser.getUpdatedAt())
            .build();
    }
}

