package com.social.media.service.impl;

import com.social.media.dto.UserDto;
import com.social.media.service.UserService;
import com.social.media.repository.UserRepository;
import com.social.media.mapper.UserMapper;
import com.social.media.domain.entity.User;
import com.social.media.domain.shared.PageResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    @Transactional(readOnly = true)
    public PageResponse<UserDto> getAllUsers(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
        Page<User> users = userRepository.findByDeletedFalse(pageable);
        
        List<UserDto> userDtos = users.getContent().stream()
                .map(userMapper::toDto)
                .collect(Collectors.toList());
        
        return PageResponse.of(userDtos, (int) users.getTotalElements(), page, size);
    }
    
    @Override
    @Transactional(readOnly = true)
    public UserDto getUserById(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado com ID: " + id));
        return userMapper.toDto(user);
    }
    
    @Override
    public UserDto createUser(UserDto userDto) {
        // Verificar se email já existe na mesma empresa
        if (userDto.getCompanyId() != null && 
            userRepository.findByCompanyIdAndEmail(userDto.getCompanyId(), userDto.getEmail()).isPresent()) {
            throw new RuntimeException("Email já está em uso nesta empresa: " + userDto.getEmail());
        }
        
        User user = userMapper.createEntity(userDto);
        User savedUser = userRepository.save(user);
        return userMapper.toDto(savedUser);
    }
    
    @Override
    public UserDto updateUser(Long id, UserDto userDto) {
        User existingUser = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado com ID: " + id));
        
        // Verificar se email já existe para outro usuário na mesma empresa
        if (!existingUser.getEmail().equals(userDto.getEmail()) && userDto.getCompanyId() != null) {
            userRepository.findByCompanyIdAndEmail(userDto.getCompanyId(), userDto.getEmail())
                    .ifPresent(user -> {
                        if (!user.getId().equals(id)) {
                            throw new RuntimeException("Email já está em uso nesta empresa: " + userDto.getEmail());
                        }
                    });
        }
        
        User updatedUser = userMapper.toEntity(userDto, existingUser);
        User savedUser = userRepository.save(updatedUser);
        return userMapper.toDto(savedUser);
    }
    
    @Override
    public void deleteUser(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado com ID: " + id));
        
        // Soft delete
        user.setDeleted(true);
        user.setUpdatedAt(LocalDateTime.now());
        userRepository.save(user);
    }
    
    @Override
    @Transactional(readOnly = true)
    public UserDto getUserByEmail(String email) {
        User user = userRepository.findByEmail(email)
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado com email: " + email));
        return userMapper.toDto(user);
    }
    
    @Override
    @Transactional(readOnly = true)
    public java.util.Optional<UserDto> findByEmail(String email) {
        return userRepository.findByEmail(email)
                .map(userMapper::toDto);
    }
    
    @Override
    @Transactional(readOnly = true)
    public PageResponse<UserDto> getUsersByRole(String role, int page, int size) {
        try {
            User.UserType userType = User.UserType.valueOf(role.toUpperCase());
            Pageable pageable = PageRequest.of(page, size, Sort.by("name"));
            Page<User> users = userRepository.findByType(userType, pageable);
            
            List<UserDto> userDtos = users.getContent().stream()
                    .map(userMapper::toDto)
                    .collect(Collectors.toList());
            
            return PageResponse.of(userDtos, (int) users.getTotalElements(), page, size);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("Tipo de usuário inválido: " + role);
        }
    }
    
    @Override
    @Transactional(readOnly = true)
    public PageResponse<UserDto> getActiveUsers(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("lastAccessDate").descending().and(Sort.by("name")));
        Page<User> users = userRepository.findActiveUsers(pageable);
        
        List<UserDto> userDtos = users.getContent().stream()
                .map(userMapper::toDto)
                .collect(Collectors.toList());
        
        return PageResponse.of(userDtos, (int) users.getTotalElements(), page, size);
    }
    
    @Override
    @Transactional(readOnly = true)
    public PageResponse<UserDto> searchUsersByName(String name, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("name"));
        Page<User> users = userRepository.findByNameContainingIgnoreCase(name, pageable);
        
        List<UserDto> userDtos = users.getContent().stream()
                .map(userMapper::toDto)
                .collect(Collectors.toList());
        
        return PageResponse.of(userDtos, (int) users.getTotalElements(), page, size);
    }
    
    @Override
    public UserDto updateLastLogin(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado com ID: " + id));
        
        user.setLastAccessDate(LocalDateTime.now());
        User savedUser = userRepository.save(user);
        return userMapper.toDto(savedUser);
    }
    
    @Override
    public UserDto updateLastAccess(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado com ID: " + id));
        
        user.setLastAccessDate(LocalDateTime.now());
        User savedUser = userRepository.save(user);
        return userMapper.toDto(savedUser);
    }
    
    @Override
    public UserDto deactivateUser(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado com ID: " + id));
        
        user.setStatus(User.UserStatus.INACTIVE);
        User savedUser = userRepository.save(user);
        return userMapper.toDto(savedUser);
    }
    
    @Override
    public UserDto activateUser(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Usuário não encontrado com ID: " + id));
        
        user.setStatus(User.UserStatus.ACTIVE);
        User savedUser = userRepository.save(user);
        return userMapper.toDto(savedUser);
    }
    
    // Fallback para manter compatibilidade com código antigo
    public List<UserDto> getAllUsers() {
        return getAllUsers(0, 10).getContent();
    }
}
