package com.codenetworkz.blog.services.impl;

import com.codenetworkz.blog.exceptions.InternalServerException;
import com.codenetworkz.blog.exceptions.UserNotFoundException;
import com.codenetworkz.blog.models.Status;
import com.codenetworkz.blog.models.User;
import com.codenetworkz.blog.repositories.UserRepository;
import com.codenetworkz.blog.services.EmailSendService;
import com.codenetworkz.blog.services.UserService;



import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;

import java.util.Optional;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;

    @Autowired(required = false)
    private EmailSendServiceImpl emailSendService;

    @Value("spring.mail.username")
    private String form;

    @Override
    public Optional<User> findByUsername(String username, String active) throws UserNotFoundException, InternalServerException {
        return getUser(Optional.ofNullable(userRepository.findByUsernameAndIsActive(username, active)));
    }


    @Override
    public Optional<User> findByEmail(String email, String active) throws UserNotFoundException, InternalServerException {
        return getUser(Optional.ofNullable(userRepository.findByEmailAndIsActive(email, active)));
    }

    @Override
    public Optional<User> findByUserById(Long userId , String active) throws UserNotFoundException, InternalServerException {
        return getUser(userRepository.findByIdAndIsActive(userId, active));
    }

    private Optional<User> getUser(Optional<User> userRepository) throws InternalServerException, UserNotFoundException {
        Optional<User> user;
        try {
            user = userRepository;
        } catch (Exception e) {
            throw new InternalServerException("There is problem with database, please try after same time.");
        }
        if (user.isPresent()) {
            return user;
        } else {
            throw new UserNotFoundException("Your are not registered, please register your account.");
        }
    }

    @Override
    public Page<User> findAll(int  pageNo, int pageSize, String filterOn1,  String filterOn2) throws InternalServerException {
        Pageable pageable;

        if(filterOn1!=null && !filterOn1.isEmpty() && filterOn2!=null && !filterOn2.isEmpty()){
            pageable =PageRequest.of(pageNo, pageSize, Sort.by(filterOn1).and(Sort.by(filterOn2)));
        }else if(filterOn1!=null && !filterOn1.isEmpty() ){
             pageable =PageRequest.of(pageNo, pageSize, Sort.by(filterOn1));
        }else if(filterOn2!=null && !filterOn2.isEmpty() ){
             pageable =PageRequest.of(pageNo, pageSize, Sort.by(filterOn1));
        }else {
             pageable = PageRequest.of(pageNo, pageSize);
        }

        try {
            return  userRepository.findAll(pageable);
        }catch (Exception e){
            throw new InternalServerException("There is problem with database, please try after same time.");
        }

    }


    @Override
    public boolean checkIfUserExists(String username, String email) throws InternalServerException {
        try {
            if(username!=null && !username.isEmpty() && email!=null && !email.isEmpty()){
                return userRepository.existsByUsernameAndEmail(username, email);
            }
            if(username!=null && !username.isEmpty() && email==null){
                return userRepository.existsByUsernameOrEmail(username, username);
            }
            return userRepository.existsByUsernameOrEmail(email, email);
        }catch (Exception e){
            throw new InternalServerException("There is problem with database, please try after same time.");
        }
    }


    @Override
    public Optional<User> save(String fristName, String lastName, String email, String password) throws UserNotFoundException, InternalServerException {

        if (!checkIfUserExists(email, email)) {
           User user = new User();
           user.setUsername(email);
           user.setFirstName(fristName);
           user.setLastName(lastName);
           user.setEmail(email);
           try {

               User saved = userRepository.save(user);
               emailSendService.sendEmail(email, "Welcome to "+fristName +" for joining blogs site." , "now your change write own blog and view others services avaliable", form );
               return Optional.of(saved);

           }catch (Exception e){
               throw new InternalServerException("There is problem with database, please try after same time.");
           }
        }
        return Optional.empty();
    }

    @Override
    public Optional<User> update(Long id, String fristName, String lastName, String username, String bio, MultipartFile profilePicture) throws UserNotFoundException, InternalServerException {
        User user=user = this.findByUserById(id, "Y").get();
        user.setFirstName(fristName);
        user.setLastName(lastName);
        user.setUsername(username);
        user.setBio(bio);
        user.setUpdateAt(LocalDateTime.now());
        //save on image on s3 or file server and get the location on update on table
        user.setProfilePictureUrl(profilePicture.getOriginalFilename());

        try {
            User saved = userRepository.save(user);

            emailSendService.sendEmail(user.getEmail(), "Your Account as been updated", "Your Account as been updated", form );
            return Optional.of(saved);
        }catch (Exception e){
            throw new InternalServerException("There is problem with database, please try after same time.");
        }

    }


    @Override
    public Optional<User> active(String email) throws UserNotFoundException, InternalServerException {
        Optional<User> userdb = findByEmail(email, "Y");
        User user = userdb.get();
        user.setIsActive(Status.YES);
        user.setUpdateAt(LocalDateTime.now());
        try {
            User saved = userRepository.save(user);

            emailSendService.sendEmail(user.getEmail(), "Your Account as been Activated", "Your Account as been Activated, try checking your account", form );
            return Optional.of(saved);
        }catch (Exception e){
            throw new InternalServerException("There is problem with database, please try after same time.");
        }
    }


    @Override
    public Optional<User> deActive(String email) throws InternalServerException, UserNotFoundException {
        Optional<User> userdb = findByEmail(email, "Y");
        User user = userdb.get();
        user.setIsActive(Status.NO);
        try {
            return Optional.of(userRepository.save(user));
        }catch (Exception e){
            throw new InternalServerException("There is problem with database, please try after same time.");
        }
    }

    @Override
    public Optional<User> delete(String email) throws InternalServerException, UserNotFoundException {
        Optional<User> userdb = findByEmail(email, "Y" );
        User user = userdb.get();
        user.setIsActive(Status.NO);
        user.setDeleteAt(LocalDateTime.now());
        //it wil just disable right now after we can recover/ activate user before 30 day,but after the user data no longer user use cant login
        try {
            return Optional.of(userRepository.save(user));
        }catch (Exception e){
            throw new InternalServerException("There is problem with database, please try after same time.");
        }
    }


    @Override
    public Optional<User> setUserRole(String username) {


        return Optional.empty();
    }

    @Override
    public Optional<User> forgotPassword(String email) throws UserNotFoundException, InternalServerException {
        User user = findByEmail(email, "Y" ).get();

        try {
           emailSendService.sendEmail(user.getEmail(), "Change your account Password", "#", form );
        }catch (Exception e){
            throw new InternalServerException("There is problem with database, please try after same time.");
        }
        return Optional.of(user);
    }

    @Override
    public Optional<User> resetPassword(String email, String password) throws UserNotFoundException, InternalServerException {
       User userdb = findByEmail(email, "Y" ).get();
        //generate password Hash

        //update object
        userdb.setPasswordHash(password);
        try {
            return Optional.of(userRepository.save(userdb));
        }catch (Exception e){
            throw new InternalServerException("There is problem with database, please try after same time.");
        }

    }

    @Service
    public static class EmailSendServiceImpl implements EmailSendService {

        @Autowired
        private JavaMailSender mailSender;

        public void sendEmail(String to, String subject, String body, String from) {

            try{
                SimpleMailMessage message = new SimpleMailMessage();
                message.setFrom(from);
                message.setTo(to);
                message.setSubject(subject);
                message.setText(body);
                mailSender.send(message);
            }catch (Exception e){
               e.printStackTrace();
            }

        }
    }
}
