package com.zanxiang.game.module.sdk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.game.module.base.pojo.enums.HttpStatusEnum;
import com.zanxiang.game.module.mybatis.entity.User;
import com.zanxiang.game.module.mybatis.entity.UserCard;
import com.zanxiang.game.module.mybatis.mapper.UserCardMapper;
import com.zanxiang.game.module.sdk.constant.RegexConstant;
import com.zanxiang.game.module.sdk.pojo.param.UserCardUpdateParam;
import com.zanxiang.game.module.sdk.pojo.param.UserData;
import com.zanxiang.game.module.sdk.service.IAliApiService;
import com.zanxiang.game.module.sdk.service.IUserBanService;
import com.zanxiang.game.module.sdk.service.IUserCardService;
import com.zanxiang.game.module.sdk.service.IUserService;
import com.zanxiang.module.util.pojo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.util.function.Tuple2;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author : lingfeng
 * @time : 2022-09-26
 * @description : 用户实名认证
 */
@Slf4j
@Service
public class UserCardServiceImpl extends ServiceImpl<UserCardMapper, UserCard> implements IUserCardService {

    @Autowired
    private IUserService userService;

    @Autowired
    private IAliApiService aliApiService;

    @Autowired
    private IUserBanService userBanService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVO<Boolean> userAuthentication(UserCardUpdateParam param, UserData userData) {
        //判断实名信息是否可用
        if (userBanService.banCheckByCardId(userData.getGameId(), param.getCardId())) {
            return ResultVO.fail(HttpStatusEnum.CARD_ID_HALT.getMsg());
        }
        //查询实名认证信息
        UserCard userCard = super.getOne(new LambdaQueryWrapper<UserCard>()
                .eq(UserCard::getUserId, userData.getUserId()));
        //已经实名认证, 不可重复认证
        if (userCard != null) {
            return ResultVO.fail(HttpStatusEnum.REPEAT_OPERATE.getMsg());
        }
        //查询玩家信息
        User user = userService.getById(userData.getUserId());
        String cardId = param.getCardId();
        String cardName = param.getCardName();
        boolean nameCheck = this.cardNameCheck(cardName);
        //名字输入不合法
        if (!nameCheck) {
            return ResultVO.fail(HttpStatusEnum.CARD_NAME_ERROR.getMsg());
        }
        boolean idCheck = this.cardIdCheck(cardId);
        //身份证号输入不合法
        if (!idCheck) {
            return ResultVO.fail(HttpStatusEnum.CARD_ID_ERROR.getMsg());
        }
        //未成年禁止认证
        if (this.getAge(cardId) < 18){
            return ResultVO.fail(HttpStatusEnum.AUTHENTICATION_FAIL_UNDERAGE.getMsg());
        }
        //阿里实名认证
        Tuple2<Boolean, String> tuple2 = aliApiService.userCardCheck(cardName, cardId);
        //实名认证失败
        if (!tuple2.getT1()) {
            return ResultVO.fail(HttpStatusEnum.AUTHENTICATION_FAIL.getMsg());
        }
        //新建记录
        this.save(UserCard.builder()
                .userId(userData.getUserId())
                .agentId(user.getAgentId())
                .username(user.getUsername())
                .nickname(user.getNickname())
                .gameId(user.getGameId())
                .regTime(user.getCreateTime())
                .cardId(cardId)
                .cardName(cardName)
                .birthday(this.getBirthday(cardId))
                .sex(this.getSex(cardId))
                .cardType(1)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .address(Strings.isBlank(tuple2.getT2()) ? null : tuple2.getT2())
                .build());
        //更新用户信息
        userService.update(new LambdaUpdateWrapper<User>()
                .set(User::getAuthentication, this.getAge(cardId) >= 18 ? 1 : 2)
                .eq(User::getId, userData.getUserId()));
        return ResultVO.ok(Boolean.TRUE);
    }

    private boolean cardNameCheck(String cardName) {
        Pattern pattern = Pattern.compile(RegexConstant.REGEX_CHINESE_NAME);
        Matcher matcher = pattern.matcher(cardName);
        return matcher.matches();
    }

    private boolean cardIdCheck(String cardId) {
        String idValid = "(" + RegexConstant.REGEX_ID_CARD18 + ")" + "|" + "(" + RegexConstant.REGEX_ID_CARD15 + ")";
        Pattern pattern = Pattern.compile(idValid);
        Matcher matcher = pattern.matcher(cardId);
        return matcher.matches();
    }

    private String getBirthday(String cardId) {
        String birthday;
        if (cardId.length() == 15) {
            birthday = "19" + cardId.substring(6, 8) + "-" + cardId.substring(8, 10) + "-" + cardId.substring(10, 12);
        } else {
            birthday = cardId.substring(6, 10) + "-" + cardId.substring(10, 12) + "-" + cardId.substring(12, 14);
        }
        return birthday;
    }

    private int getAge(String cardId) {
        String birthday;
        if (cardId.length() == 15) {
            birthday = "19" + cardId.substring(6, 8);
        } else {
            birthday = cardId.substring(6, 14);
        }
        Date birthDate = null;
        try {
            birthDate = new SimpleDateFormat("yyyyMMdd").parse(birthday);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (birthDate == null) {
            return 0;
        }
        GregorianCalendar currentDay = new GregorianCalendar();
        currentDay.setTime(birthDate);
        int birYear = currentDay.get(Calendar.YEAR);
        // 获取年龄
        return LocalDate.now().getYear() - birYear;
    }

    private int getSex(String cardId) {
        int sex;
        if (cardId.length() == 15) {
            sex = Integer.parseInt(cardId.substring(cardId.length() - 3)) % 2 == 0 ? 2 : 1;
        } else {
            sex = Integer.parseInt(cardId.substring(cardId.length() - 4, cardId.length() - 1)) % 2 == 0 ? 2 : 1;
        }
        return sex;
    }

}
