package kr.co.jinwoosi.clfd.clfd.user.service;

import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;
import kr.co.jinwoosi.clfd.framework.mail.MailService;
import kr.co.jinwoosi.clfd.framework.security.mapper.UserMapper;
import kr.co.jinwoosi.clfd.framework.security.model.User;
import kr.co.jinwoosi.clfd.framework.security.model.UserRole;
import kr.co.jinwoosi.clfd.framework.security.model.UserSearch;
import kr.co.jinwoosi.clfd.framework.security.service.UserRoleService;
import kr.co.jinwoosi.clfd.framework.security.service.UserService;
import kr.co.jinwoosi.clfd.framework.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ClfdUserService {

    @Autowired
    private UserService userService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private MailService mailService;

    public Map<String, Object> selectUser(UserSearch userSearch) {
        Map<String, Object> result = new HashMap<String, Object>();
        User user = userMapper.select(userSearch);

        if (user == null) {
            result.put("result", "fail");
            result.put("message", "사용자를 찾을 수 없습니다.");
            return result;
        }

        UserRole userRole = new UserRole();
        userRole.setUserId(user.getUserId());
        userRole = userRoleService.select(userRole);

        result.put("result", "success");
        result.put("user", user);
        result.put("role", userRole.getRoleAuth());

        return result;
    }

    public void updateUser(User user) {
        userMapper.update(user);
    }

    public Map<String, String> updatePwd(Long userId, String userLoginId, String password, String newPassword) throws Exception {
        Map<String, String> result = new HashMap<>();

        String encryptPassword = StrUtil.encryptSha512(password, userLoginId);
        String encryptNewPassword = StrUtil.encryptSha512(newPassword, userLoginId);

        if (userPwdCheck(new UserSearch(userId, encryptPassword)) < 1) {
            result.put("result", "fail");
            result.put("message", "기존 비밀번호가 일치하지 않습니다.");
            return result;
        }

        if (encryptPassword.equals(encryptNewPassword)) {
            result.put("result", "fail");
            result.put("message", "이전 비밀번호와 같은 비밀번호 입니다.");
            return result;
        }

        User user = new User();
        user.setUserId(userId);
        user.setUpdId(userId);
        user.setUserPwd(encryptNewPassword);

        try {
            updateUser(user);
        } catch (RuntimeException e) {
            result.put("result", "fail");
            result.put("message", "비밀번호를 변경하는 중 오류가 발생하였습니다.");
        }


        result.put("result", "success");
        result.put("message", "비밀번호가 변경되었습니다.");
        return result;
    }

    public int userPwdCheck(UserSearch userSearch) {
        return userMapper.userPwdCheck(userSearch);
    }

    public void join(User user) {
        UserSearch userSearch = new UserSearch();
        userSearch.setUserLoginId(user.getUserLoginId());

        if (userService.checkIdDuplicate(userSearch) > 0) {
            throw new RuntimeException("사용자를 등록하는 도중 오류가 발생하였습니다.");
        }

        /*
         * SMS 인증 일 경우 authStCd를 1로 처리
         */
        user.setAuthStCd("1");

        /*
         * 이메일 인증 부분 주석처리
         */
//        String authKey = StrUtil.getRandomPassword(16);
//        String authCode = passwordEncoder.encode(authKey);
//        user.setAuthKey(authKey);

        userService.insert(user);

        Long userId = user.getUserId();

        UserRole userRole = new UserRole();
        userRole.setUserId(userId);
        String userTyCd = user.getUserTyCd();

        if (userTyCd != null) {
            if (userTyCd.equals("U")) {
                userRole.setRoleAuth("ROLE_USER");
                userRoleService.insert(userRole);
            } else if (userTyCd.equals("M")) {
                userRole.setRoleAuth("ROLE_MANAGER");
                userRoleService.insert(userRole);
            } else {
                throw new RuntimeException("사용자 타입 코드가 명시되지 않았습니다.");
            }
        } else {
            throw new RuntimeException("사용자 타입 코드가 명시되지 않았습니다.");
        }

        /*
         * 이메일 인증 부분 주석처리
         */
//        String email = null;
//        if (userTyCd.equals("J")) {
//            email = user.getManagerEmail();
//        } else if (userTyCd.equals("U")) {
//            email = user.getEmail();
//        }
//        if (email != null) {
//            mailService.gmailSend(
//                    email,
//                    MailService.EmailTitle.JOIN_AUTH.getTitle(),
//                    mailService.getLoginMailText(user.getUserLoginId(), authCode)
//            );
//        }

    }

    /**
     * 접속 사용자 아이디(번호)를 가져 온다.
     *
     * @return
     */
    public Long getUserId() {
        if ("anonymousUser".equals(EgovUserDetailsHelper.getAuthenticatedUser())) return null;

        User user = (User) EgovUserDetailsHelper.getAuthenticatedUser();
        if (user != null) {
            return user.getUserId();
        }

        return null;
    }

    /**
     * 접속 사용자의 로그인 아이디를 가져온다.
     *
     * @return
     */
    public String getUserLoginId() {
        User user =
                (User) EgovUserDetailsHelper.getAuthenticatedUser();
        if (user != null) {
            return user.getUserLoginId();
        }
        return null;
    }

    /**
     * 접속한 사용자의 이름을 가져온다.
     *
     * @return
     */
    public String getUserName() {
        User user =
                (User) EgovUserDetailsHelper.getAuthenticatedUser();
        if (user != null) {
            return user.getUserNm();
        }
        return null;
    }

    /**
     * 이메일 인증을 처리
     *
     * @return 이메일 인증에 성공하면 true, 실패하면 false
     */
    public boolean emailAuth(String id, String authCode) {
        UserSearch userSearch = new UserSearch();
        userSearch.setUserLoginId(id);
        User user = userMapper.select(userSearch);
        // 인증할 사용자가 없는 경우
        if (user == null) {
            return false;
        }

        if (user.getAuthStCd() == null) {
            if (passwordEncoder.matches(user.getAuthKey(), authCode)) {
                User updateUser = new User();
                updateUser.setUserId(user.getUserId());
                updateUser.setUserLoginId(id);
                updateUser.setAuthStCd("1");
                userMapper.update(updateUser);
                return true;
            } else {
                return false;
            }
        } else if (user.getAuthStCd().equals("1")) {
            return false;
        } else {
            return false;
        }
    }

    /**
     * 아이디 찾기를 처리 (휴대폰 인증 시 사용)
     *
     * @return 찾은 아이디 목록을 반환
     */
    public List<String> findLoginIdByPhone(String phone) {
        UserSearch userSearch = new UserSearch();
        userSearch.setFindIdByPhoneFlag(true);
        userSearch.setPhone(phone);
        List<User> users = userMapper.selectList(userSearch);
        List<String> loginIdList = users.stream().map(User::getUserLoginId).collect(Collectors.toList());
        return loginIdList;
    }

    /**
     * 비밀번호 찾기를 처리 (휴대폰 인증 시 사용)
     *
     * @return Map<String, Object>
     * isFind: true, false
     * loginId: -
     * password: -
     * message: -
     */
    public Map<String, Object> findPasswordForSms(String loginId, String phone) {
        Map<String, Object> result = new HashMap<>();
        UserSearch userSearch = new UserSearch();
        userSearch.setFindPwByPhoneAndIdFlag(true);
        userSearch.setPhone(phone);
        userSearch.setUserLoginId(loginId);
        List<User> users = userMapper.selectList(userSearch);
        if (users.size() == 0) {
            result.put("isFind", Boolean.FALSE);
            result.put("message", "아이디와 휴대폰 번호를 확인하세요.");
            return result;
        }
        User user = users.get(0);
        String tempPassword = StrUtil.getRandomPassword(10);

        String encryptPassword = null;
        try {
            encryptPassword = StrUtil.encryptSha512(tempPassword, user.getUserLoginId());
        } catch (Exception e) {
            result.put("isFind", Boolean.FALSE);
            result.put("message", "비밀번호 찾기중 문제가 발생하였습니다.");
            return result;
        }

        result.put("isFind", Boolean.TRUE);
        result.put("loginId", user.getUserLoginId());
        result.put("password", tempPassword);
        result.put("message", "비밀번호 찾기를 완료하였습니다.");

        User updateUser = new User();
        Long userId = user.getUserId();
        updateUser.setUserId(userId);
        updateUser.setUpdId(userId);
        updateUser.setUserPwd(encryptPassword);
        updateUser(updateUser);
        return result;
    }

    /**
     * 아이디 찾기를 처리 (이메일 인증 시 사용)
     *
     * @return 아이디를 찾으면 true, 아이디를 못찾으면 false
     */
    public boolean findIdByEmail(String email) {
        UserSearch userSearch = new UserSearch();
        userSearch.setEmail(email);
        List<User> users = userMapper.selectList(userSearch);
        if (users.size() == 0) {
            return false;
        }
        List<String> loginIdList = users.stream().map(User::getUserLoginId).collect(Collectors.toList());
        mailService.gmailSend(
                email,
                MailService.EmailTitle.FIND_ID.getTitle(),
                mailService.getFindIdText(loginIdList)
        );
        return true;
    }

    /**
     * 비밀번호 찾기를 처리 (이메일 인증 시 사용)
     *
     * @return 입력한 아이디가 존재하고 해당 아이디의 이메일과 입력한 이메일이 동일하면 true, 아이디를 못찾거나 이메일이 다르면 false
     */
    public boolean findPassword(String userLoginId, String email) throws Exception {
        UserSearch userSearch = new UserSearch();
        userSearch.setUserLoginId(userLoginId);
        List<User> userLoginIdList = userMapper.selectList(userSearch);
        if (userLoginIdList.size() == 0) {
            return false;
        } else if (!userLoginIdList.get(0).getEmail().equals(email)) {
            return false;
        }
        String tempPassword = StrUtil.getRandomPassword(10);
        mailService.gmailSend(
                email,
                MailService.EmailTitle.FIND_PW.getTitle(),
                mailService.getFindPasswordText(tempPassword)
        );

        String encryptPassword = StrUtil.encryptSha512(tempPassword, userLoginId);
        User user = new User();
        Long userId = userLoginIdList.get(0).getUserId();
        user.setUserId(userId);
        user.setUpdId(userId);
        user.setUserPwd(encryptPassword);
        updateUser(user);
        return true;
    }

}
