package com.seer.teach.user.app.auth.service.strategy;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import com.seer.teach.common.constants.CommonConstant;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.enums.RoleEnum;
import com.seer.teach.common.enums.UserRelationEnum;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.mp.api.WechatMiniProgramApi;
import com.seer.teach.mp.api.resp.WxMiniProgramSessionDTO;
import com.seer.teach.user.app.auth.LoginType;
import com.seer.teach.user.app.auth.request.LoginParam;
import com.seer.teach.user.app.auth.service.LoginStrategy;
import com.seer.teach.user.app.auth.service.LoginUser;
import com.seer.teach.user.entity.UserAuthEntity;
import com.seer.teach.user.entity.UserEntity;
import com.seer.teach.user.entity.UserFamilyEntity;
import com.seer.teach.user.entity.UserRelationEntity;
import com.seer.teach.user.service.IUserAuthService;
import com.seer.teach.user.service.IUserFamilyService;
import com.seer.teach.user.service.IUserRelationService;
import com.seer.teach.user.service.IUserRoleService;
import com.seer.teach.user.service.IUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


/**
 * 微信小程序登录策略
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class MiniProgramLoginStrategy extends AbstractLoginStrategy implements LoginStrategy {


    private final WechatMiniProgramApi wechatMiniProgramApi;

    private final IUserService userService;

    private final IUserRelationService userRelationService;

    private final IUserAuthService userAuthService;

    private final IUserRoleService userRoleService;

    private final IUserFamilyService userFamilyService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Value("${zs.login.check.qrcode.expired:false}")
    private boolean isChickQrCodeExpired;

    @Override
    public LoginType getType() {
        return LoginType.WECHAT_MINI;
    }

    @Override
    public LoginUser authenticate(LoginParam request) {
        WxMiniProgramSessionDTO wxMiniProgramSessionDTO = wechatMiniProgramApi.code2Session(request.getJsCode());
        AssertUtils.isTrue(wxMiniProgramSessionDTO.isSuccess(), ResultCodeEnum.WX_OAUTH_USED_ERROR);
        UserAuthEntity userAuth = userAuthService.getOneByOpenIdAndUnionId(wxMiniProgramSessionDTO.getOpenid(), wxMiniProgramSessionDTO.getUnionid());
        boolean isExistsChildren = false;
        if (userAuth != null) {
            userAuth.setAppId(request.getAppId());
            updateUserAuth(userAuth);

            isExistsChildren = userRelationService.getChildrenUserCountByUserId(userAuth.getUserId()) > 0;

            if (!isExistsChildren && isScanQrCodeLogin(request)) {
                saveUserRelations(request.getScene(), userAuth.getUserId());
                isExistsChildren = true;
            }
            log.info("用户[{}]登陆成功", userAuth.getUserId());
            return new LoginUser(userAuth.getUserId(), isExistsChildren);
        }
        log.info("用户未绑定微信");
        UserEntity user = userService.getOneByUnionId(wxMiniProgramSessionDTO.getUnionid());
        if (user != null) {
            // 是否有孩子
            isExistsChildren = userRelationService.getChildrenUserCountByUserId(user.getId()) > 0;
            if (!isExistsChildren && isScanQrCodeLogin(request)) {
                saveUserRelations(request.getScene(), user.getId());
                isExistsChildren = true;
            }
            saveUserAuth(getType().getCode(), user.getId(), wxMiniProgramSessionDTO);
            return new LoginUser(user.getId(), isExistsChildren);
        }
        UserEntity userEntity = new UserEntity();
        userEntity.setUnionId(wxMiniProgramSessionDTO.getUnionid());

        boolean saved = userService.save(userEntity);
        log.info("保存用户信息：{}", saved);

        saveUserAuth(getType().getCode(), userEntity.getId(), wxMiniProgramSessionDTO);
        userRoleService.assignUserRoleByRoleCode(userEntity.getId(), RoleEnum.PARENT.getCode());
        if (isScanQrCodeLogin(request)) {
            log.info("用户[{}]扫描加入家庭的二维码登录,家庭Id：{}", userEntity.getId(), request.getScene());
            saveUserRelations(request.getScene(), userEntity.getId());
            isExistsChildren = true;
        }
        return new LoginUser(userEntity.getId(), isExistsChildren);
    }

    private void saveUserRelations(String scene, Integer userId) {
        log.info("用户[{}]扫描二维码登录的场景值：{}", userId, scene);
        Integer familyId = Integer.parseInt(scene);
        UserFamilyEntity family = userFamilyService.getById(familyId);
        AssertUtils.notNull(family, ResultCodeEnum.USER_FAMILY_NOT_EXIST);
        log.info("用户[{}]加入家庭[{}]", userId, familyId);

        List<UserRelationEntity> childRelations = userRelationService.getUserRelationsByFamilyIdAndType(familyId, UserRelationEnum.PARENT_CHILD);
        AssertUtils.notNull(childRelations, ResultCodeEnum.USER_FAMILY_NOT_EXIST);

        List<UserRelationEntity> userRelations = userRelationService.getUserRelationByUserIdAndType(userId, UserRelationEnum.PARENT_CHILD);
        if (CollectionUtil.isNotEmpty(userRelations)) {
            UserRelationEntity childRelation = userRelations.get(0);
            UserRelationEntity parentRelation = userRelations.get(0);
            if (Objects.nonNull(childRelation.getFamilyId()) && Objects.nonNull(parentRelation.getFamilyId()) && childRelation.getFamilyId().intValue() == parentRelation.getFamilyId()) {
                throw new CommonException(ResultCodeEnum.USER_FAMILY_MEMBER_EXIST);
            }
            if (Objects.nonNull(childRelation.getFamilyId()) && childRelation.getFamilyId().intValue() == familyId) {
                throw new CommonException(ResultCodeEnum.USER_FAMILY_REPEAT_EXIST);
            }
        }
        List<UserRelationEntity> parentRelations = new ArrayList<>(userRelations.size());
        childRelations.forEach(childRelation -> {
            UserRelationEntity newRelation = new UserRelationEntity();
            newRelation.setUserId(userId);
            newRelation.setIsDefault(childRelation.getIsDefault());
            newRelation.setRelationId(childRelation.getRelationId());
            newRelation.setType(UserRelationEnum.PARENT_CHILD.getCode());
            newRelation.setFamilyId(familyId);
            parentRelations.add(newRelation);
        });
        boolean saveBatch = userRelationService.saveBatch(parentRelations);
        log.info("保存用户关系：{}", saveBatch);
    }

    /**
     * 是否是扫码登录
     *
     * @param request 登录参数
     * @return boolean true 是扫码登录，false 密码登录
     */
    private boolean isScanQrCodeLogin(LoginParam request) {
        if (!StringUtils.hasText(request.getScene())) {
            return false;
        }
        log.info("用户扫描二维码登录的场景值：{}", request.getScene());
        if (!NumberUtil.isNumber(request.getScene())) {
            return false;
        }
        if(isChickQrCodeExpired){
            String redisKey = CommonConstant.WX_MINI_QR_SCENE_PREFIX + request.getScene();
            Boolean hasKey = redisTemplate.hasKey(redisKey);
            log.info("二维码场景值在redis中[{}]是否存在：{}", request.getScene(), hasKey);
            return hasKey;
        }
        return true;
    }
}