package com.social.media.infrastructure.persistence.user.query;

import com.social.media.application.user.query.UserQueryService;
import com.social.media.domain.user.aggregate.User;
import com.social.media.domain.user.valueobject.UserId;
import com.social.media.infrastructure.persistence.mapper.UserEntityMapper;
import com.social.media.infrastructure.persistence.repository.UserJpaRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

/**
 * Implementation of UserQueryService using JPA - REFACTORED VERSION
 * All operations now require userId and companyId for security isolation
 */
@Service
@Transactional(readOnly = true)
public class UserQueryServiceImpl implements UserQueryService {
    
    private final UserJpaRepository userJpaRepository;
    private final UserEntityMapper userEntityMapper;
    
    public UserQueryServiceImpl(UserJpaRepository userJpaRepository,
                              UserEntityMapper userEntityMapper) {
        this.userJpaRepository = userJpaRepository;
        this.userEntityMapper = userEntityMapper;
    }
    
    /**
     * Find user by ID with security validation
     */
    public Optional<User> findByIdWithSecurity(UserId userId, Long requestingUserId, Long companyId) {
        return userJpaRepository.findByIdAndCompanyIdAndRequestingUserId(
                userId.value(), companyId, requestingUserId)
                .map(userEntityMapper::toDomain);
    }
    
    /**
     * Get user's own profile
     */
    public Optional<User> findOwnProfile(UserId userId, Long companyId) {
        return userJpaRepository.findOwnProfile(userId.value(), companyId)
                .map(userEntityMapper::toDomain);
    }
    
    /**
     * Find all users in company with security validation
     */
    public Page<User> findAllByCompany(Long companyId, Long requestingUserId, Pageable pageable) {
        return userJpaRepository.findByCompanyIdAndRequestingUserId(companyId, requestingUserId, pageable)
                .map(userEntityMapper::toDomain);
    }
    
    /**
     * Find users by company and status with security validation
     */
    public Page<User> findByCompanyAndStatus(Long companyId, String status, Long requestingUserId, Pageable pageable) {
        // Convert string status to enum - this will need to be adjusted based on your enum
        var statusEntity = convertToStatusEntity(status);
        return userJpaRepository.findByCompanyIdAndStatusAndRequestingUserId(
                companyId, statusEntity, requestingUserId, pageable)
                .map(userEntityMapper::toDomain);
    }
    
    /**
     * Find users by company and type with security validation
     */
    public Page<User> findByCompanyAndUserType(Long companyId, String userType, Long requestingUserId, Pageable pageable) {
        // Convert string userType to enum - this will need to be adjusted based on your enum
        var userTypeEntity = convertToUserTypeEntity(userType);
        return userJpaRepository.findByCompanyIdAndUserTypeAndRequestingUserId(
                companyId, userTypeEntity, requestingUserId, pageable)
                .map(userEntityMapper::toDomain);
    }
    
    /**
     * Find user by email within company
     */
    public Optional<User> findByEmailAndCompany(String email, Long companyId) {
        return userJpaRepository.findByEmail(email)
                .map(userEntityMapper::toDomain);
    }
    
    /**
     * Check if email exists within company
     */
    public boolean existsByEmailAndCompany(String email, Long companyId) {
        return userJpaRepository.existsByEmailAndCompanyId(email, companyId);
    }
    
    /**
     * Check if CPF exists within company
     */
    public boolean existsByCpfAndCompany(String cpf, Long companyId) {
        return userJpaRepository.existsByCpfAndCompanyId(cpf, companyId);
    }
    
    /**
     * Find subordinates (users managed by requesting user)
     */
    public Page<User> findSubordinates(Long companyId, Long requestingUserId, Pageable pageable) {
        return userJpaRepository.findSubordinates(companyId, requestingUserId, pageable)
                .map(userEntityMapper::toDomain);
    }
    
    /**
     * Count users by company with security validation
     */
    public long countByCompany(Long companyId, Long requestingUserId) {
        return userJpaRepository.countByCompanyIdAndRequestingUserId(companyId, requestingUserId);
    }
    
    // Legacy methods - DEPRECATED - keeping for backward compatibility
    // These should be replaced with security-aware versions
    
    @Override
    @Deprecated
    public Optional<User> findById(UserId userId) {
        throw new UnsupportedOperationException("Use findByIdWithSecurity instead - requires userId and companyId");
    }
    
    @Override
    @Deprecated
    public Page<User> findAll(Pageable pageable) {
        throw new UnsupportedOperationException("Use findAllByCompany instead - requires companyId and requestingUserId");
    }
    
    @Override
    @Deprecated
    public Page<User> findByCompanyId(Long companyId, Pageable pageable) {
        throw new UnsupportedOperationException("Use findAllByCompany instead - requires requestingUserId");
    }
    
    @Override
    @Deprecated
    public Page<User> findByUserType(String userType, Pageable pageable) {
        throw new UnsupportedOperationException("Use findByCompanyAndUserType instead - requires companyId and requestingUserId");
    }
    
    @Override
    @Deprecated
    public Optional<User> findByEmail(String email) {
        throw new UnsupportedOperationException("Use findByEmailAndCompany instead - requires companyId");
    }
    
    @Override
    @Deprecated
    public boolean existsByEmail(String email) {
        throw new UnsupportedOperationException("Use existsByEmailAndCompany instead - requires companyId");
    }
    
    @Override
    @Deprecated
    public boolean existsByCpf(String cpf) {
        throw new UnsupportedOperationException("Use existsByCpfAndCompany instead - requires companyId");
    }
    
    // Helper methods for enum conversion
    private com.social.media.infrastructure.persistence.entity.UserStatusEntity convertToStatusEntity(String status) {
        // This needs to be implemented based on your actual enum
        return com.social.media.infrastructure.persistence.entity.UserStatusEntity.valueOf(status.toUpperCase());
    }
    
    private com.social.media.infrastructure.persistence.entity.UserTypeEntity convertToUserTypeEntity(String userType) {
        // This needs to be implemented based on your actual enum
        return com.social.media.infrastructure.persistence.entity.UserTypeEntity.valueOf(userType.toUpperCase());
    }
}
