package com.emonster.taroaichat.service;

import com.emonster.taroaichat.domain.User;
import com.emonster.taroaichat.domain.UserProfile;
import com.emonster.taroaichat.repository.UserProfileRepository;
import com.emonster.taroaichat.service.dto.UserProfileDTO;
import com.emonster.taroaichat.service.mapper.UserProfileMapper;
import java.util.Optional;

import com.emonster.taroaichat.web.rest.errors.BadRequestAlertException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Service Implementation for managing {@link com.emonster.taroaichat.domain.UserProfile}.
 */
@Service
@Transactional
public class UserProfileService {

    private static final Logger LOG = LoggerFactory.getLogger(UserProfileService.class);

    private final UserProfileRepository userProfileRepository;

    private final UserProfileMapper userProfileMapper;
    
    private final UserService userService;

    public UserProfileService(UserProfileRepository userProfileRepository, UserProfileMapper userProfileMapper, UserService userService) {
        this.userProfileRepository = userProfileRepository;
        this.userProfileMapper = userProfileMapper;
        this.userService = userService;
    }

    /**
     * Save a userProfile.
     *
     * @param userProfileDTO the entity to save.
     * @return the persisted entity.
     */
    public UserProfileDTO save(UserProfileDTO userProfileDTO) {
        LOG.debug("Request to save UserProfile : {}", userProfileDTO);
        UserProfile userProfile = userProfileMapper.toEntity(userProfileDTO);
        userProfile = userProfileRepository.save(userProfile);
        return userProfileMapper.toDto(userProfile);
    }

    /**
     * Update a userProfile.
     *
     * @param userProfileDTO the entity to save.
     * @return the persisted entity.
     */
    public UserProfileDTO update(UserProfileDTO userProfileDTO) {
        LOG.debug("Request to update UserProfile : {}", userProfileDTO);
        UserProfile userProfile = userProfileMapper.toEntity(userProfileDTO);
        userProfile.setIsPersisted();
        userProfile = userProfileRepository.save(userProfile);
        return userProfileMapper.toDto(userProfile);
    }

    /**
     * Partially update a userProfile.
     *
     * @param userProfileDTO the entity to update partially.
     * @return the persisted entity.
     */
    public Optional<UserProfileDTO> partialUpdate(UserProfileDTO userProfileDTO) {
        LOG.debug("Request to partially update UserProfile : {}", userProfileDTO);

        return userProfileRepository
            .findById(userProfileDTO.getId())
            .map(existingUserProfile -> {
                userProfileMapper.partialUpdate(existingUserProfile, userProfileDTO);

                return existingUserProfile;
            })
            .map(userProfileRepository::save)
            .map(userProfileMapper::toDto);
    }

    /**
     * Get all the userProfiles with eager load of many-to-many relationships.
     *
     * @return the list of entities.
     */
    public Page<UserProfileDTO> findAllWithEagerRelationships(Pageable pageable) {
        return userProfileRepository.findAllWithEagerRelationships(pageable).map(userProfileMapper::toDto);
    }

    /**
     * Get one userProfile by id.
     *
     * @param id the id of the entity.
     * @return the entity.
     */
    @Transactional(readOnly = true)
    public Optional<UserProfileDTO> findOne(Long id) {
        LOG.debug("Request to get UserProfile : {}", id);
        return userProfileRepository.findOneWithEagerRelationships(id).map(userProfileMapper::toDto);
    }

    /**
     * Get one userProfile by user id.
     *
     * @param userId the user id.
     * @return the entity.
     */
    @Transactional(readOnly = true)
    public Optional<UserProfileDTO> findByUserId(Long userId) {
        LOG.debug("Request to get UserProfile by User ID : {}", userId);
        return userProfileRepository.findByUserId(userId).map(userProfileMapper::toDto);
    }

    /**
     * Delete the userProfile by id.
     *
     * @param id the id of the entity.
     */
    public void delete(Long id) {
        LOG.debug("Request to delete UserProfile : {}", id);
        userProfileRepository.deleteById(id);
    }

    /**
     * Get current user's profile ID.
     *
     * @return the current user's profile ID
     */
    @Transactional(readOnly = true)
    public Optional<Long> getCurrentUserProfileId() {
        LOG.debug("Request to get current user's profile ID");
        
        return userService.getUserWithAuthorities()
            .flatMap(user -> userProfileRepository.findByUserId(user.getId()))
            .map(UserProfile::getId);
    }

    /**
     * Update user profile with explicit null handling.
     * This method ensures that null values are properly saved to the database.
     *
     * @param userProfileDTO the entity to update
     * @return the updated entity
     */
    public UserProfileDTO updateWithNulls(UserProfileDTO userProfileDTO) {
        LOG.debug("Request to update UserProfile with nulls : {}", userProfileDTO);
        
        // Find the existing entity
        UserProfile existingEntity = userProfileRepository.findById(userProfileDTO.getId())
            .orElseThrow(() -> new BadRequestAlertException("Failed to update profile", "UserProfile", "updatefailed"));
        
        // Update all fields explicitly, including nulls
        existingEntity.setBirthday(userProfileDTO.getBirthday());
        existingEntity.setGender(userProfileDTO.getGender());
        existingEntity.setOccupation(userProfileDTO.getOccupation());
        
        // Save and return
        UserProfile savedEntity = userProfileRepository.save(existingEntity);
        return userProfileMapper.toDto(savedEntity);
    }
}
