package com.koobietech.eas.service.impl;

import com.alibaba.fastjson2.JSON;
import com.anji.captcha.model.common.ResponseModel;
import com.koobietech.eas.common.exception.EasException;
import com.koobietech.eas.common.pojo.JwtUserPojo;
import com.koobietech.eas.common.result.JsonResult;
import com.koobietech.eas.common.utils.FileManager;
import com.koobietech.eas.common.utils.JwtManager;
import com.koobietech.eas.common.utils.PasswordManager;
import com.koobietech.eas.common.utils.SecurityManager;
import com.koobietech.eas.dao.constant.JwtType;
import com.koobietech.eas.dao.constant.UserType;
import com.koobietech.eas.dao.dto.LoginTokenDto;
import com.koobietech.eas.dao.mapper.AdminLoginMapper;
import com.koobietech.eas.dao.mapper.UserProFileMapper;
import com.koobietech.eas.dao.pojo.AdminPojo;
import com.koobietech.eas.dao.pojo.DepartmentPojo;
import com.koobietech.eas.dao.pojo.UserDetailPojo;
import com.koobietech.eas.dao.pojo.UserProFilePojo;
import com.koobietech.eas.mbg.mapper.EasSysUserinfoMapper;
import com.koobietech.eas.mbg.model.EasSysUserinfo;
import com.koobietech.eas.mbg.model.EasSysUserinfoExample;
import com.koobietech.eas.service.EasSysAdminLoginService;
import com.koobietech.eas.service.EasSysUserLoginRedisService;
import com.koobietech.eas.service.config.EasAuthorityConfig;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Service
public class EasSysAdminLoginServiceImpl implements EasSysAdminLoginService {

    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private PasswordManager passwordManager;
    @Resource
    private AdminLoginMapper adminLoginMapper;
    @Resource
    private EasSysUserinfoMapper easSysUserinfoMapper;
    @Resource
    private EasSysUserLoginRedisService loginRedisService;

    @Resource
    private UserProFileMapper userProFileMapper;

    @Resource
    private JwtManager jwtManager;
    @Resource
    FileManager fileManager;

    @Value("${authority.path}")
    String jsonFilePath;

    // token过期时间 单位：s
    private final Integer token_expires = 24 * 60 * 60;
    private final Integer refreshToken_expires = 48 * 60 * 60;

    @Override
    public LoginTokenDto adminLogin(AdminPojo adminPojo) {
        if (adminPojo.getUsername() == null || adminPojo.getPasswd() == null || adminPojo.getUsername().isEmpty() || adminPojo.getPasswd().isEmpty()) {
            throw new EasException("用户不存在", 412);
        }

        EasSysUserinfo easSysUserinfo = findAdminByUsername(adminPojo.getUsername(), adminPojo.getPasswd());

        // 接收到对象，根据这个信息去查询数据库，然后自定义sql查用户信息，存在redis里面当做token
        System.out.println(easSysUserinfo);
        //先获取id，进行枚举判断
        Long id = easSysUserinfo.getId();
        //先调用自定义sql查询detail类中的数据 最后把这个类封装到redis里面
        UserDetailPojo userDetailPojoInRedis = adminLoginMapper.getUserDetailById(id);

        userDetailPojoInRedis.setDepartments(adminLoginMapper.getUserDepartmentsById(id));
        List<DepartmentPojo> departments = userDetailPojoInRedis.getDepartments();

        //权限配置文件
//        String absolutePath = new File(jsonFilePath).getAbsolutePath();
//        FileInputStream archiveFile = fileManager.getArchiveFile(absolutePath);
        String absolutePath = "temp/authority.json";
        InputStream archiveFile = getClass().getClassLoader().getResourceAsStream(absolutePath);

        String jsonStr = "";
        try {
            jsonStr = IOUtils.toString(archiveFile, "UTF-8");
        } catch (IOException ignored) {}

        EasAuthorityConfig easAuthorityConfig = JSON.parseObject(jsonStr, EasAuthorityConfig.class);
        if (easAuthorityConfig == null) {
            throw new EasException("权限配置文件不存在", 412);
        }
        departments.forEach(departmentPojo -> {
            try {
                String authority = departmentPojo.getAuthority();
                if ( authority != null && !authority.isEmpty() ) {
                    String methodName = Character.toUpperCase(authority.charAt(0)) + authority.substring(1);
                    Method declaredMethod = easAuthorityConfig.getClass().getDeclaredMethod("get" + methodName, null);
                    if ( declaredMethod != null ) {
                        List<String> depUrlList = (List<String>) declaredMethod.invoke(easAuthorityConfig, null);
                        if (Objects.nonNull(depUrlList) && depUrlList.size() > 0 ) {
                            if ( Objects.nonNull(userDetailPojoInRedis.getPermissionPojos()) ) {
                                depUrlList.addAll(userDetailPojoInRedis.getPermissionPojos());
                            }
                            userDetailPojoInRedis.setPermissionPojos(depUrlList);
                        }
                    }
                }
            } catch (NoSuchMethodException ignored) {}
            catch (IllegalAccessException ignored) {}
            catch (InvocationTargetException ignored) {}
        });


        // 此处的用户类型 主要给前端构建菜单用, 后台配置菜单太麻烦了
        UserType userType = UserType.teacher;
        if (userDetailPojoInRedis.getUsername().equals("admin")) {
            userType = UserType.admin;
        }
        userDetailPojoInRedis.setUserType(userType);

        // 生成token
        JwtUserPojo jwtUserPojo = new JwtUserPojo(userDetailPojoInRedis.getUsername(),
                userDetailPojoInRedis.getId(), userType, JwtType.TOKEN);
        JwtUserPojo refJwtUserPojo = new JwtUserPojo(userDetailPojoInRedis.getUsername(),
                userDetailPojoInRedis.getId(), userType, JwtType.REF_TOKEN);
        String token = jwtManager.createJwt(jwtUserPojo, token_expires);
        String refreshToken = jwtManager.createJwt(refJwtUserPojo, refreshToken_expires);
        System.out.println("token:" + token);
        System.out.println("refreshToken:" + refreshToken);

        // 生成redis key
        String redisTokenKey = loginRedisService.createJwtTokenKey(jwtUserPojo);
        String redisRefreshTokenKey = loginRedisService.createJwtRefreshTokenKey(jwtUserPojo);

        // 将token存入redis
        loginRedisService.loginSaveCache(redisTokenKey, userDetailPojoInRedis, token_expires);
        loginRedisService.loginSaveCache(redisRefreshTokenKey, userDetailPojoInRedis, refreshToken_expires);

        // 登录成功
        return new LoginTokenDto(token, refreshToken);
    }

    @Override
    public LoginTokenDto refreshToken(String refreshToken) {
        // 解析refresh token
        JwtUserPojo jwtUserPojo = jwtManager.decodeJwt(refreshToken);

        //生成新的 刷新k值 （refresh_token）
        String newRedisRefreshTokenKey = loginRedisService.createJwtRefreshTokenKey(jwtUserPojo);

        //查询redis里面有没有这个k值
        UserDetailPojo userDetailPojoInRedis = loginRedisService.loginGetCache(newRedisRefreshTokenKey);
        if (userDetailPojoInRedis == null) {
            throw new EasException("refresh token已过期", 412);
        }
        //如果不为空 那UserDetail里面就封装了用户的信息 生成新的token和refresh token
        String newRefreshToken = jwtManager.createJwt(jwtUserPojo, refreshToken_expires);

        jwtUserPojo.setJwtType(JwtType.TOKEN);
        String newToken = jwtManager.createJwt(jwtUserPojo, token_expires);

        //生成新的k值 （token）
        String newRedisTokenKey = loginRedisService.createJwtTokenKey(jwtUserPojo);

        // 更新Redis中的token和refresh token
        loginRedisService.loginSaveCache(newRedisTokenKey, userDetailPojoInRedis, token_expires);
        loginRedisService.loginSaveCache(newRedisRefreshTokenKey, userDetailPojoInRedis, refreshToken_expires);
        return new LoginTokenDto(newToken, newRefreshToken);
    }


    @Override
    public JsonResult verifyToJsonResult(ResponseModel response) {
        JsonResult result = new JsonResult();

        if (response != null) {
            result.setMsg(response.getRepMsg());
            result.setStatus(response.isSuccess());
            result.setData(response.getRepData());
            result.setCode( Integer.parseInt(response.getRepCode()) );
        }
        else {
            throw new EasException("ResponseModel参数为空！",9000);
        }

        return result;
    }

    @Override
    public UserDetailPojo getUserInfo(String token) {

        try {
            // 解析token
            JwtUserPojo jwtUserPojo = jwtManager.decodeJwt(token);
            // 封装成字符以便在redis中查找
            String tokenToRedisKey = loginRedisService.createJwtTokenKey(jwtUserPojo);
            return loginRedisService.loginGetCache(tokenToRedisKey);
        } catch (Exception e) {
            // 处理异常情况
            throw new EasException("Token获取用户信息失败", e);
        }}

    @Override
    public UserProFilePojo getUserProFile() {
        UserProFilePojo userProFilePojo;
        if ( SecurityManager.isStudentUser() ) {
            userProFilePojo = userProFileMapper
                    .getStudentProFile(SecurityManager.getLoginSid().intValue());
        } else {
            userProFilePojo = userProFileMapper
                    .getUserProFile(SecurityManager.getLoginUid().intValue());
        }
        return  userProFilePojo;
    }

    @Override
    public boolean uploadUserProFile(UserProFilePojo userProFilePojo) {
        boolean success;
        if ( ObjectUtils.isEmpty(userProFilePojo)) {
            throw new EasException("上传用户错误！",9000);
        }
        //强制密码规则 限制对密码试探
        if ( Objects.nonNull(userProFilePojo.getPasswd())
                && !"".equals(userProFilePojo.getPasswd())) {
            userProFilePojo.setPasswd(passwordEncoder.encode(userProFilePojo.getPasswd()));;
        } else {
            userProFilePojo.setPasswd(null);
        }
        if ( SecurityManager.isStudentUser() ) {
            userProFilePojo.setId( SecurityManager.getLoginSid().intValue() );
            int i = userProFileMapper.updateStudentProFile(userProFilePojo);
            success = i > 0;
        } else {
            userProFilePojo.setId( SecurityManager.getLoginUid().intValue() );
            int i = userProFileMapper.updateUserProFile(userProFilePojo);
            success = i > 0;
        }
        return success;
    }

    @Override
    public boolean logout() {
        JwtUserPojo jwtUserPojo = new JwtUserPojo();
        jwtUserPojo.setType(SecurityManager.getUserType());
        jwtUserPojo.setUsername(SecurityManager.getLoginUserName());
        jwtUserPojo.setId( SecurityManager.isStudentUser() ? SecurityManager.getLoginSid() : SecurityManager.getLoginUid() );
        return loginRedisService.loginDeleteCache(jwtUserPojo);
    }


    private EasSysUserinfo findAdminByUsername(String username, String password)  {
        EasSysUserinfoExample easSysUserinfoExample = new EasSysUserinfoExample();
        easSysUserinfoExample.createCriteria().andUsernameEqualTo(username);
        List<EasSysUserinfo> adminList = easSysUserinfoMapper.selectByExample(easSysUserinfoExample);

        // 使用Optional简化判断
        Optional<EasSysUserinfo> optionalAdmin = adminList.stream().findFirst();

        if (optionalAdmin.isEmpty()) {
            throw new EasException("用户不存在", 9902);
        }
        if (adminList.size() > 1) {
            throw new EasException("用户数据异常", 9902);
        }

        EasSysUserinfo easSysUserinfo = optionalAdmin.get();

        // 验证密码 这个方法里面有解密 如果解密失败会抛出异常
        validatePassword(password, easSysUserinfo.getPasswd());

        return easSysUserinfo;
    }


    private void validatePassword(String inputPassword, String encryptedPassword){
        String decryptedPassword = passwordManager.decryptPassword(inputPassword);
        if (!passwordEncoder.matches(decryptedPassword, encryptedPassword)) {
            throw new EasException("密码不正确", 9901);
        }
    }
}
