package com.mmc.iuav.user.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.mmc.iuav.auth.JwtConstant;
import com.mmc.iuav.auth.JwtUtil;
import com.mmc.iuav.general.CodeUtil;
import com.mmc.iuav.http.BizException;
import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.response.ResultEnum;
import com.mmc.iuav.user.auth.PwdUtil;
import com.mmc.iuav.user.client.PayClient;
import com.mmc.iuav.user.constant.WxConstant;
import com.mmc.iuav.user.dao.CompanyAuthDao;
import com.mmc.iuav.user.entity.CompanyAuthDO;
import com.mmc.iuav.user.entity.UserAccountDO;
import com.mmc.iuav.user.enums.UserAccountStatus;
import com.mmc.iuav.user.model.dto.LoginSuccessDTO;
import com.mmc.iuav.user.model.qo.LoginUserQO;
import com.mmc.iuav.user.model.vo.AppUserSucVO;
import com.mmc.iuav.user.model.vo.UserAccountVO;
import com.mmc.iuav.user.model.vo.WxLoginVO;
import com.mmc.iuav.user.service.AuthService;
import com.mmc.iuav.user.service.UserAccountService;
import com.mmc.iuav.user.service.WxService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: zj
 * @Date: 2023/5/16 13:51
 */
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private WxService wxService;

    @Autowired
    private UserAccountService userAccountService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private CompanyAuthDao companyAuthDao;

    @Autowired
    private PayClient payClient;

    @Transactional
    @Override
    public ResultBody appletLogin(WxLoginVO wxLoginVO) {
        String unionId;
        String openId;
        String sessionKey;
        if (wxLoginVO.getFromPort().toString().equals(WxConstant.APP.toString())) {
            //调用小程序登录接口，里面包含unionId
            String appWxJson = wxService.appLogin(wxLoginVO);
            if (StringUtils.isBlank(appWxJson)) {
                return ResultBody.error(ResultEnum.APPLET_PORT_TYPE_ERROR);
            }
            log.info("wx appLogin msg==>" + JSONObject.toJSONString(appWxJson));
            JSONObject json = JSON.parseObject(appWxJson);
            if (!json.containsKey(WxConstant.OPEN_ID) || !json.containsKey(WxConstant.SESSION_KEY)) {
                log.error("wx appLogin error==>" + JSONObject.toJSONString(json));
                return ResultBody.error(ResultEnum.APPLET_LOGIN_ERROR, json);
            }
            unionId = json.getString(WxConstant.UNION_ID);
            openId = json.getString(WxConstant.OPEN_ID);
            sessionKey = json.getString(WxConstant.SESSION_KEY);
        }else if (wxLoginVO.getFromPort().equals(WxConstant.WEB)){
            //获取access_token接口，里面包含unionId
            String pcWxJson = wxService.pcLogin(wxLoginVO);
            if (StringUtils.isBlank(pcWxJson)) {
                return ResultBody.error(ResultEnum.APPLET_PORT_TYPE_ERROR);
            }
            log.info("wx pcLogin msg==>" + JSONObject.toJSONString(pcWxJson));
            JSONObject json = JSON.parseObject(pcWxJson);
            if (!json.containsKey(WxConstant.OPEN_ID) ||!json.containsKey(WxConstant.SESSION_KEY)) {
                log.error("wx pcLogin error==>" + JSONObject.toJSONString(json));
                return ResultBody.error(ResultEnum.APPLET_LOGIN_ERROR, json);
            }
            unionId = json.getString(WxConstant.UNION_ID);
            openId = json.getString(WxConstant.OPEN_ID);
            sessionKey = json.getString(WxConstant.SESSION_KEY);
        }else {
            return ResultBody.error(ResultEnum.PARAM_ERROR);
        }
        //数据库查询用户信息
        UserAccountVO userAccountVO = userAccountService.getUserAccountInfoByUnionId(unionId);
        String uid;
        Integer companyAuthStatus = 0;
        if (userAccountVO == null) {
            UserAccountDO userAccountDO = new UserAccountDO();
            userAccountDO.setUnionId(unionId);
            userAccountDO.setOpenId(openId);
            uid = CodeUtil.generateUserUID();
            userAccountDO.setUid(uid);
            userAccountDO.setAccountType(0);
            userAccountDO.setPortType(100);
            userAccountDO.setSource(wxLoginVO.getSource());
            userAccountService.insertUserAccount(userAccountDO);
            userAccountVO = userAccountDO.buildUserAccountVO();
            payClient.createWallet(userAccountDO.getId());
        }else {
            uid = userAccountVO.getUid();
            CompanyAuthDO companyAuthDO = companyAuthDao.getCompanyAuth(userAccountVO.getId());
            if (companyAuthDO != null) {
                companyAuthStatus = companyAuthDO.getAuthStatus();
            }
        }
        Map<String, Object> map = new HashMap<String, Object>();
        map.put(JwtConstant.USER_ACCOUNT_ID, userAccountVO.getId());
        //map.put(JwtConstant.ROLE_ID, 0);
        map.put(JwtConstant.TOKEN_TYPE, JwtConstant.IUAV_TOKEN);
        String token = JwtUtil.createJwt(map);

        LoginSuccessDTO loginSuccessDTO = LoginSuccessDTO.builder().token(token).userAccountId(userAccountVO.getId()).accountNo(userAccountVO.getAccountNo()).uid(uid)
                .userName(userAccountVO.getUserName()).nickName(userAccountVO.getNickName()).phoneNum(userAccountVO.getPhoneNum()).portType(100).build();

        stringRedisTemplate.opsForValue().set(
                token, JSONObject.toJSONString(loginSuccessDTO),
                JwtConstant.EXPIRATION, TimeUnit.MILLISECONDS);

        return ResultBody.success(AppUserSucVO.builder().token(token).uid(userAccountVO.getUid()).phoneNum(userAccountVO.getPhoneNum())
                .nickName(userAccountVO.getNickName()).userAccountId(userAccountVO.getId()).sessionKey(sessionKey).portType(100).authStatus(companyAuthStatus).build());
    }

    @Override
    public ResultBody backEndLogin(LoginUserQO param) {
        //查询用户信息
        UserAccountDO user = userAccountService.getUserLoginInfo(param.getAccountNo(), param.getPassWord());
        if (user == null) {
            return ResultBody.error(ResultEnum.LOGIN_ACCOUNT_NOT_EXIT_ERROR);
        }
        if (user.getAccountStatus() .equals(UserAccountStatus.DISABLE.getAccountStatus()) ) {
            return ResultBody.error(ResultEnum.LOGIN_ACCOUNT_STATUS_ERROR);
        }
        String loginPwd = "";
        try {
            loginPwd = PwdUtil.securityPwd(param.getPassWord());
        } catch (NoSuchAlgorithmException e) {
            return ResultBody.error(ResultEnum.PWD_CONPARED_ERROR);
        }
        if (!loginPwd.equals(user.getPassword())) {
            return ResultBody.error(ResultEnum.LOGIN_PASSWORD_ERROR);
        }

        Map<String, Object> map = new HashMap<String, Object>();
        map.put(JwtConstant.USER_ACCOUNT_ID, user.getId());
        //map.put(JwtConstant.ROLE_ID, 0);
        map.put(JwtConstant.TOKEN_TYPE, JwtConstant.M_TOKEN);
        String token = JwtUtil.createJwt(map);
        LoginSuccessDTO loginSuccessDTO = LoginSuccessDTO.builder().token(token).userAccountId(user.getId()).accountNo(user.getAccountNo()).uid(user.getUid())
                .userName(user.getUserName()).nickName(user.getNickName()).phoneNum(user.getPhoneNum()).portType(user.getPortType()).build();
        stringRedisTemplate.opsForValue().set(
                token, JSONObject.toJSONString(loginSuccessDTO),
                JwtConstant.EXPIRATION, TimeUnit.MILLISECONDS);

        return ResultBody.success(LoginSuccessDTO.builder().token(token).userAccountId(user.getId()).accountNo(user.getAccountNo()).build());
    }

    @Override
    public ResultBody testAppletLogin(String unionId) {
        UserAccountVO userAccountVO = userAccountService.getUserAccountInfoByUnionId(unionId);
        if (userAccountVO != null) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put(JwtConstant.USER_ACCOUNT_ID, userAccountVO.getId());
            map.put(JwtConstant.TOKEN_TYPE, JwtConstant.IUAV_TOKEN);
            CompanyAuthDO companyAuthDO = companyAuthDao.getCompanyAuth(userAccountVO.getId());
            Integer companyAuthStatus = 0;
            if (companyAuthDO != null) {
                companyAuthStatus = companyAuthDO.getAuthStatus();
            }
            String token = JwtUtil.createJwt(map);
            LoginSuccessDTO loginSuccessDTO = LoginSuccessDTO.builder().token(token).userAccountId(userAccountVO.getId()).accountNo(userAccountVO.getAccountNo()).uid(userAccountVO.getUid())
                    .userName(userAccountVO.getUserName()).nickName(userAccountVO.getNickName()).phoneNum(userAccountVO.getPhoneNum()).portType(100).build();
            stringRedisTemplate.opsForValue().set(
                    token, JSONObject.toJSONString(loginSuccessDTO),
                    JwtConstant.EXPIRATION, TimeUnit.MILLISECONDS);

            return ResultBody.success(AppUserSucVO.builder().token(token).uid(userAccountVO.getUid()).phoneNum(userAccountVO.getPhoneNum())
                    .nickName(userAccountVO.getNickName()).userAccountId(userAccountVO.getId()).portType(100).authStatus(companyAuthStatus).build());
        }
        return ResultBody.error(ResultEnum.APPLET_LOGIN_ERROR);
    }

    @Override
    public ResultBody tempConfirmLogin(LoginSuccessDTO loginSuccessDTO, String randomLoginCode) {
        stringRedisTemplate.opsForValue().set(
                randomLoginCode, JSONObject.toJSONString(loginSuccessDTO),
                JwtConstant.TEMP_EXPIRATION, TimeUnit.MILLISECONDS);
        return ResultBody.success();
    }

    @Override
    public ResultBody getLoginInfo(String randomLoginCode) {
        String json = stringRedisTemplate.opsForValue().get(randomLoginCode);
        if (StringUtils.isBlank(json)){
            return ResultBody.error(ResultEnum.APPLET_LOGIN_ERROR);
        }
        LoginSuccessDTO loginSuccessDTO = JSONObject.parseObject(json, LoginSuccessDTO.class);
        return ResultBody.success(loginSuccessDTO);
    }
}
