package ovh.herisson.Clyde.Services;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Repositories.UserRepository;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User;
import java.util.*;

@Service
public class UserService {
    private final UserRepository userRepo;
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    public UserService(UserRepository userRepo){
        this.userRepo = userRepo;
    }


    /** return the user identified by th identifier
     *
     * @param identifier can be an email or the RegNo
     * @return the identified user
     */
    public User getUser(String identifier){
        if (identifier == null)
            return null;

        try {
            int id = Integer.parseInt(identifier);
            return userRepo.findById(id);
        }
        catch (NumberFormatException nfe){
            return userRepo.findByEmail(identifier);
        }
    }

    /** modify the target data
     * verify the permission of modifying from the poster
     *
     * @param poster the user wanting to modify target's data
     * @param updates the changes to be made
     * @param targetId the id of the user to update
     * @return if the changes were done or not
     */
    public boolean modifyData(long targetId, Map<String ,Object> updates, User poster){

        User target = userRepo.findById(targetId);
        if (target == null)
            return false;

        if (poster.getRegNo().equals(target.getRegNo())){
            for (Map.Entry<String, Object> entry : updates.entrySet()){

                switch (entry.getKey()){
                    case "firstName":
                        target.setFirstName((String) entry.getValue());
                        break;
                    case "lastName":
                        target.setLastName((String) entry.getValue());
                        break;
                    case "email":
                        target.setEmail((String) entry.getValue());
                        break;
                    case "address":
                        target.setAddress((String) entry.getValue());
                        break;
                    case "country":
                        target.setCountry((String) entry.getValue());
                        break;
                    case "birthDate":
                        target.setBirthDate((Date) entry.getValue());
                        break;
                    case "profilePictureUrl":
                        target.setProfilePictureUrl((String) entry.getValue());
                        break;
                    case "password":
                        target.setPassword(passwordEncoder.encode((String) entry.getValue()));
                        break;
                }
            }
            userRepo.save(target);
            return true;
        }
        // the secretary can change roles (for example if a student becomes a teacher)
        else if (poster.getRole() == Role.Secretary)
        {
            for (Map.Entry<String, Object> entry : updates.entrySet()){

                if ( entry.getKey().equals("role")) {

                    if (entry.getValue() == Role.Admin) {return false;}

                    target.setRole((Role) entry.getValue());
                    userRepo.save(target);
                    return true;
                }
            }
        }
        return false;
    }


    public boolean checkPassword(User user, String tryingPassword){
        return passwordEncoder.matches(tryingPassword,  user.getPassword());
    }

    public User save(User  user){
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return userRepo.save(user);
    }

    public Iterable<User> getAll(){
        return userRepo.findAll();
    }

    public Iterable<User> getAllExceptAdmins(){
        return userRepo.findAllExceptAdmins();
    }


    public Iterable<User> getAllTeachers (){return userRepo.findAllTeachers();}

    public Iterable<User> getAllStudents(){return userRepo.findAllStudents();}


    public User getUserById(long id) {
        return userRepo.findById(id);
    }
}
