package com.social.media.application.user.handler;

import com.social.media.application.user.command.CreateUserCommand;
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.user.valueobject.*;
import com.social.media.domain.shared.valueobject.Email;
import com.social.media.domain.shared.valueobject.Phone;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;

/**
 * Handler for CreateUserCommand
 */
@Service
@Transactional
public class CreateUserCommandHandler {
    
    private final UserRepository userRepository;
    private final UserDomainService userDomainService;
    private final PasswordEncoder passwordEncoder;
    
    public CreateUserCommandHandler(UserRepository userRepository, 
                                  UserDomainService userDomainService,
                                  PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.userDomainService = userDomainService;
        this.passwordEncoder = passwordEncoder;
    }
    
    public UserResponseDto handle(CreateUserCommand command) {
        // Get creator user for validation
        User createdBy = null;
        if (command.createdBy() != null) {
            createdBy = userRepository.findById(command.createdBy())
                .orElseThrow(() -> new BusinessRuleViolationException("Creator user not found"));
        }
        
        // Validate business rules using domain service
        userDomainService.validateUserCreation(command.type(), command.companyId(), createdBy);
        
        // Validate email and CPF uniqueness
        validateEmailNotExists(command.email());
        if (command.cpf() != null) {
            validateCpfNotExists(command.cpf());
        }
        
        // Create value objects
        Email email = new Email(command.email());
        Phone phone = command.phone() != null ? new Phone(command.phone()) : null;
        Cpf cpf = command.cpf() != null ? new Cpf(command.cpf()) : null;
        
        // Encode password
        String encodedPassword = passwordEncoder.encode(command.password());
        
        // Create user aggregate
        User user = User.create(
            command.name(),
            email,
            encodedPassword,
            command.type(),
            command.companyId()
        );
        
        // Set optional fields
        if (cpf != null) {
            user.setCpf(cpf);
        }
        if (phone != null) {
            user.updateProfile(user.getName(), phone, command.position(), command.department());
        } else if (command.position() != null || command.department() != null) {
            user.updateProfile(user.getName(), user.getPhone(), command.position(), command.department());
        }
        
        if (command.whatsappEnabled()) {
            user.enableWhatsapp();
        }
        
        // Save user
        User savedUser = userRepository.save(user);
        
        // Return DTO
        return mapToDto(savedUser);
    }
    
    private void validateEmailNotExists(String email) {
        if (userRepository.existsByEmail(new Email(email))) {
            throw new BusinessRuleViolationException("Email already exists: " + email);
        }
    }
    
    private void validateCpfNotExists(String cpf) {
        if (userRepository.existsByCpf(new Cpf(cpf))) {
            throw new BusinessRuleViolationException("CPF already exists: " + cpf);
        }
    }
    
    private UserResponseDto mapToDto(User user) {
        return UserResponseDto.builder()
            .id(user.getId().value().toString())
            .name(user.getName())
            .email(user.getEmail().value())
            .phone(user.getPhone() != null ? user.getPhone().value() : null)
            .position(user.getPosition())
            .department(user.getDepartment())
            .status(user.getStatus().name())
            .companyId(user.getCompanyId().value().toString())
            .avatarUrl(user.getAvatarUrl())
            .emailVerified(user.isEmailVerified())
            .whatsappEnabled(user.isWhatsappEnabled())
            .lastAccessDate(user.getLastAccessDate())
            .permissions(user.getPermissions().permissions())
            .configuration(Map.of(
                "timezone", user.getConfiguration().timezone(),
                "language", user.getConfiguration().language(),
                "preferences", user.getConfiguration().preferences()
            ))
            .createdAt(user.getCreatedAt())
            .updatedAt(user.getUpdatedAt())
            .build();
    }
}

