package com.xinelu.applet.service.personappletlogin.Impl;

import com.xinelu.applet.mapper.nursemanagepersonwechatinfo.NurseManagePersonWechatInfoMapper;
import com.xinelu.applet.mapper.personappletlogin.PersonAppletLoginMapper;
import com.xinelu.applet.service.personappletlogin.PersonAppletLoginService;
import com.xinelu.applet.utils.AppletAccessTokenUtil;
import com.xinelu.applet.vo.personappletlogin.PersonAppletVO;
import com.xinelu.applet.vo.personappletlogin.UserAndRole;
import com.xinelu.common.config.NurseAppletChatConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.entity.AppletLoginVO;
import com.xinelu.common.entity.AppletPhoneVO;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.AppletChatUtil;
import com.xinelu.manage.domain.nursemanagepersonwechatinfo.NurseManagePersonWechatInfo;
import com.xinelu.manage.mapper.nursestationperson.NurseStationPersonMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description 护理员微信小程序登录注册业务层实现类
 * @Author zh
 * @Date 2023-03-30
 * @Version 1.0
 */
@Slf4j
@Service
public class PersonAppletLoginServiceImpl implements PersonAppletLoginService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private NurseAppletChatConfig nurseAppletChatConfig;
    @Resource
    private AppletAccessTokenUtil appletAccessTokenUtil;
    @Resource
    private NurseStationPersonMapper nurseStationPersonMapper;
    @Resource
    private PersonAppletLoginMapper personAppletLoginMapper;
    @Resource
    private NurseManagePersonWechatInfoMapper nurseManagePersonWechatInfoMapper;

    /**
     * 返回成功状态码
     */
    private static final int SUCCESS_CODE = 0;

    /**
     * 获取微信小程序access_token错误码
     */
    private static final int ERROR_ACCESS_CODE = 40001;

    /**
     * 返回成功状态码
     */
    private static final String OK = "ok";

    /**
     * 根据登录凭证获取用户的登录信息
     *
     * @param loginCode 登录凭证
     * @return 微信用户登录信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult personAppletLogin(String loginCode, String phoneCode) {
        //根据code获取用户的微信unionId以及openId等信息
        AppletLoginVO appletLoginInfo = AppletChatUtil.getAppletLoginInfo(nurseAppletChatConfig.getAppletId(), nurseAppletChatConfig.getSecret(), loginCode, nurseAppletChatConfig.getGrantType());
        if (Objects.isNull(appletLoginInfo)) {
            return AjaxResult.error("获取微信小程序用户信息失败");
        }
        if (Objects.nonNull(appletLoginInfo.getErrcode()) && appletLoginInfo.getErrcode() != SUCCESS_CODE) {
            return AjaxResult.error("获取微信小程序用户信息失败，失败信息为：" + appletLoginInfo.getErrmsg());
        }
        //获取微信accessToken,从Redis中取出accessToken
        String accessToken;
        String accessTokenKey = Constants.NURSE_STATION_PERSON_APPLET_ACCESS_TOKEN + "accessToken";
        Object object = redisTemplate.opsForValue().get(accessTokenKey);
        if (Objects.isNull(object)) {
            accessToken = appletAccessTokenUtil.getPersonAppletAccessToken();
        } else {
            accessToken = (String) object;
        }
        //获取用户手机号
        AppletPhoneVO appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
        if (Objects.isNull(appletPhoneInfo)) {
            return AjaxResult.error("获取用户手机号失败");
        }
        if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
            //当前Redis缓存中的access_token无效直接删除
            if (Objects.nonNull(object)) {
                redisTemplate.delete(accessTokenKey);
                accessToken = appletAccessTokenUtil.getPersonAppletAccessToken();
                appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
                if (Objects.isNull(appletPhoneInfo)) {
                    return AjaxResult.error("获取用户手机号失败");
                }
                if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
                    return AjaxResult.error("登录失败！");
                }
            }
        }
        if (StringUtils.isNotBlank(appletPhoneInfo.getErrmsg()) && !OK.equals(appletPhoneInfo.getErrmsg())) {
            return AjaxResult.error("获取用户手机号失败，失败信息为：" + appletPhoneInfo.getErrmsg());
        }
        PersonAppletVO personAppletVO = getPersonApplet(appletPhoneInfo, appletLoginInfo);
        return AjaxResult.success(personAppletVO);
    }

    /**
     * 护理站管理人员微信个人信息对象
     *
     * @param phone   护理员手机号
     * @param openid  用户的信息
     * @param sysUser 管理员信息
     */
    private void getNurseManagePersonWechat(String phone, String openid, List<UserAndRole> sysUser) {
        //护理站管理人员微信个人信息对象
        NurseManagePersonWechatInfo nurseManagePersonWechat = nurseManagePersonWechatInfoMapper.selectNurseManagePersonWechatInfoByPhone(phone);
        NurseManagePersonWechatInfo nurseManagePersonWechatInfo = new NurseManagePersonWechatInfo();
        if (Objects.isNull(nurseManagePersonWechat)) {
            nurseManagePersonWechatInfo.setOpenid(openid);
            nurseManagePersonWechatInfo.setPhone(phone);
            nurseManagePersonWechatInfo.setNurseStationId(StringUtils.isBlank(sysUser.get(0).getNurseStationIds()) ? "" : sysUser.get(0).getNurseStationIds());
            nurseManagePersonWechatInfo.setUserId(Objects.isNull(sysUser.get(0).getUserId()) ? null : sysUser.get(0).getUserId());
            nurseManagePersonWechatInfo.setCreateTime(LocalDateTime.now());
            int count = nurseManagePersonWechatInfoMapper.insertNurseManagePersonWechatInfo(nurseManagePersonWechatInfo);
            if (count <= 0) {
                throw new ServiceException("新增护理站管理人员微信个人信息失败，请联系管理员！");
            }
        }
        if (Objects.nonNull(nurseManagePersonWechat)) {
            nurseManagePersonWechatInfo.setId(Objects.isNull(nurseManagePersonWechat.getId()) ? null : nurseManagePersonWechat.getId());
            nurseManagePersonWechatInfo.setOpenid(openid);
            nurseManagePersonWechatInfo.setPhone(phone);
            nurseManagePersonWechatInfo.setNurseStationId(StringUtils.isBlank(sysUser.get(0).getNurseStationIds()) ? "" : sysUser.get(0).getNurseStationIds());
            nurseManagePersonWechatInfo.setUserId(Objects.isNull(sysUser.get(0).getUserId()) ? null : sysUser.get(0).getUserId());
            int update = nurseManagePersonWechatInfoMapper.updateNurseManagePersonWechatInfo(nurseManagePersonWechatInfo);
            if (update <= 0) {
                throw new ServiceException("新增护理站管理人员微信个人信息失败，请联系管理员！");
            }
        }
    }

    /**
     * 护理员登录接口方法抽取
     *
     * @param appletPhoneInfo 微信用户信息
     * @param appletLoginInfo 手机号信息
     * @return 登录标识
     */
    private PersonAppletVO getPersonApplet(AppletPhoneVO appletPhoneInfo, AppletLoginVO appletLoginInfo) {
        PersonAppletVO appletParent = new PersonAppletVO();
        String phone = StringUtils.isBlank(appletPhoneInfo.getPhoneInfo().getPhoneNumber()) ? "" : appletPhoneInfo.getPhoneInfo().getPhoneNumber();
        String openid = StringUtils.isBlank(appletLoginInfo.getOpenid()) ? "" : appletLoginInfo.getOpenid();
        PersonAppletVO nurseStationPerson = personAppletLoginMapper.getNurseStationPersonByPhone(phone);
        List<UserAndRole> sysUser = personAppletLoginMapper.selectSysUser(phone);
        //说明当前用户角色即是：护理员又是护理站运营人员
        if (Objects.nonNull(nurseStationPerson) && CollectionUtils.isNotEmpty(sysUser)) {
            //更新用户的openid等微信标识信息
            this.updateNurseStationPerson(appletParent, nurseStationPerson, openid);
            appletParent.setPersonRoleLoginFlag(Constants.PERSON_ROLE_NAME);
            //护理站管理人员微信个人信息对象
            List<String> roleKeyList = sysUser.stream().filter(Objects::nonNull).map(UserAndRole::getRoleKey).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(roleKeyList) && (String.join((","), roleKeyList).contains(Constants.STATION_ROLE_NAME))) {
                this.getNurseManagePersonWechat(phone, openid, sysUser);
                appletParent.setPersonRoleLoginFlag(Constants.STATION_AND_PERSON_ROLE_NAME);
            }
        }
        //说明当前用户角色即是：护理员
        if (Objects.nonNull(nurseStationPerson) && Objects.isNull(sysUser)) {
            //更新用户的openid等微信标识信息
            this.updateNurseStationPerson(appletParent, nurseStationPerson, openid);
            appletParent.setPersonRoleLoginFlag(Constants.PERSON_ROLE_NAME);
        }
        //说明当前用户角色即是：护理站运营人员
        if (Objects.isNull(nurseStationPerson) && Objects.nonNull(sysUser)) {
            List<String> roleKeyList = sysUser.stream().filter(Objects::nonNull).map(UserAndRole::getRoleKey).collect(Collectors.toList());
            appletParent.setPersonRoleLoginFlag(Constants.NOT_ROLE_NAME);
            if (CollectionUtils.isNotEmpty(roleKeyList) && (String.join((","), roleKeyList).contains(Constants.STATION_ROLE_NAME))) {
                this.getNurseManagePersonWechat(phone, openid, sysUser);
                appletParent.setPersonRoleLoginFlag(Constants.STATION_ROLE_NAME);
            }
            appletParent.setPhone(phone);
        }
        //说明当前用户角色即是：即不是护理员又是不是护理站运营人员
        if (Objects.isNull(nurseStationPerson) && Objects.isNull(sysUser)) {
            appletParent.setPhone(phone);
            appletParent.setPersonRoleLoginFlag(Constants.NOT_ROLE_NAME);
        }
        //当前用户角色只要包含护理员，那么将护理员的信息返回给前端
        if (Objects.nonNull(nurseStationPerson)) {
            appletParent.setNurseStationId(Objects.isNull(nurseStationPerson.getNurseStationId()) ? null : nurseStationPerson.getNurseStationId());
            appletParent.setNurseStationPersonId(Objects.isNull(nurseStationPerson.getNurseStationPersonId()) ? null : nurseStationPerson.getNurseStationPersonId());
            appletParent.setNursePersonName(StringUtils.isBlank(nurseStationPerson.getNursePersonName()) ? "" : nurseStationPerson.getNursePersonName());
        }
        return appletParent;
    }

    /**
     * 修改护理人员信息
     *
     * @param appletParent       护理员信息
     * @param nurseStationPerson 护理员信息
     * @param openid             护理员信息
     */
    private void updateNurseStationPerson(PersonAppletVO appletParent, PersonAppletVO nurseStationPerson, String openid) {
        appletParent.setId(nurseStationPerson.getNurseStationPersonId());
        appletParent.setNurseStationPersonId(nurseStationPerson.getNurseStationPersonId());
        appletParent.setOpenid(openid);
        appletParent.setPhone(StringUtils.isBlank(nurseStationPerson.getPhone()) ? "" : nurseStationPerson.getPhone());
        appletParent.setUpdateTime(LocalDateTime.now());
        int updateCount = nurseStationPersonMapper.updateNurseStationPerson(appletParent);
        if (updateCount <= 0) {
            throw new ServiceException("修改护理人员信息失败，请联系管理员！");
        }
    }
}


