package ru.soune.nocopy.service.user;

import lombok.AllArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.soune.nocopy.dto.register.ChangePasswordRequest;
import ru.soune.nocopy.dto.user.UserDTO;
import ru.soune.nocopy.dto.user.UserRequest;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.InvalidUserEmail;
import ru.soune.nocopy.exception.NotValidationPasswordException;
import ru.soune.nocopy.exception.UserNotFoundException;
import ru.soune.nocopy.repository.UserRepository;

import java.util.List;
import java.util.Optional;

@Service
@AllArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    private final PasswordEncoder passwordEncoder;

    @Transactional
    public User changePassword(User user, ChangePasswordRequest request) {
        if (!passwordEncoder.matches(request.getCurrentPassword(), user.getPassword())) {
            throw new NotValidationPasswordException("Current password is incorrect");
        }

        user.setPassword(passwordEncoder.encode(request.getNewPassword()));

        return userRepository.save(user);
    }

    @Transactional
    public UserDTO updateUser(UserRequest userRequest, User currentUser) {
        User user = userRepository.findById(currentUser.getId())
                .orElseThrow(() -> new UserNotFoundException("User not found with id: " + currentUser.getId()));

        updateUserFromRequest(user, userRequest);

        User updatedUser = userRepository.save(user);

        return mapToDTO(updatedUser);
    }

    @Transactional
    public List<String> getUsersCompanyEmails(String company) {
        return userRepository.emailsByCompany(company);
    }

    @Transactional
    public User activateAndVerifyUser(long userId) {
        Optional<User> users = userRepository.findById(userId);
        User user = users.orElseThrow(() -> new UserNotFoundException("User not found with id: " + userId));
        user.setActive(true);
        user.setEmailVerified(true);

        return userRepository.save(user);
    }

    private void updateUserFromRequest(User user, UserRequest request) {
        if (request.getFullName() != null) {
            user.setFullName(request.getFullName());
        }

        if (request.getEmail() != null && !request.getEmail().equals(user.getEmail())) {
            if (userRepository.existsByEmail(request.getEmail())) {
                throw new InvalidUserEmail("Email already exists: " + request.getEmail());
            }
            user.setEmail(request.getEmail());
        }

        if (request.getPhone() != null) {
            user.setPhone(request.getPhone());
        }
        if (request.getGenderType() != null) {
            user.setGenderType(request.getGenderType());
        }
        if (request.getBirthday() != null) {
            user.setBirthday(request.getBirthday());
        }
    }

    private UserDTO mapToDTO(User user) {
        return UserDTO.builder()
                .fullName(user.getFullName())
                .email(user.getEmail())
                .company(user.getCompanyName())
                .phone(user.getPhone())
                .genderType(user.getGenderType())
                .birthday(user.getBirthday())
                .subscriptionType(user.getSubscriptionType())
                .createdAt(user.getCreatedAt())
                .build();
    }
}
