package com.liquidnet.service.adam.controller;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.liquidnet.common.third.shumei.util.ShumeiUtil;
import com.liquidnet.commons.lang.constant.LnsEnum;
import com.liquidnet.commons.lang.constant.LnsRegex;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.IDCardUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.commons.lang.util.SensitizeUtil;
import com.liquidnet.service.adam.constant.AdamConst;
import com.liquidnet.service.adam.dto.AdamThirdPartParam;
import com.liquidnet.service.adam.dto.AdamUserInfoParam;
import com.liquidnet.service.adam.dto.param.AdamIdentityParam;
import com.liquidnet.service.adam.dto.vo.*;
import com.liquidnet.service.adam.service.AdamRdmService;
import com.liquidnet.service.adam.service.IAdamUserInfoService;
import com.liquidnet.service.adam.service.IAdamUserService;
import com.liquidnet.service.adam.util.ObjectUtil;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

@ApiSupport(order = 10020)
@Api(tags = "用户中心")
@Slf4j
@Validated
@RestController
@RequestMapping("user")
public class AdamUserController {
    @Autowired
    Environment env;
    @Value("${liquidnet.reviewer.user-info}")
    private Boolean reviewUserInfo;

    @Autowired
    AdamRdmService adamRdmService;
    @Autowired
    IAdamUserService adamUserService;
    @Autowired
    IAdamUserInfoService adamUserInfoService;
//    @Autowired
//    IAdamUserBusiAcctService adamUserBusiAcctService;
    @Autowired
    private ShumeiUtil shumeiUtil;

    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "资料编辑")
    @PostMapping(value = {"edit"})
    public ResponseDto<AdamUserInfoVo> edit(@Valid @RequestBody AdamUserInfoParam parameter) {
        log.debug("parameter:{}", JsonUtils.toJson(parameter));

        AdamTagVo sex = parameter.getSex();
//        if (null == sex) {
//            return ResponseDto.failure(ErrorMapping.get("10011"));
//        }
        if (null != sex) {
            String sexVal = sex.getVal();
            List<AdamTagVo> allSexTagVos = this.getTagsForSex().getData();
            Optional<AdamTagVo> existSexTagVoOptional = allSexTagVos.stream().filter(r -> r.getVal().equals(sexVal)).findAny();
            if (!existSexTagVoOptional.isPresent()) {
                // 已选中的性别标签不在系统性别标签库中
                return ResponseDto.failure(ErrorMapping.get("10011"));
            }
            sex = existSexTagVoOptional.get();
        }
//        List<AdamTagParentVo> tagMeVos = parameter.getTagMe();
//        if (null == tagMeVos) {
//            return ResponseDto.failure(ErrorMapping.get("10012"));
//        }
//        List<String> chooseTagMeParentVals = tagMeVos.stream().map(AdamTagParentVo::getVal).collect(Collectors.toList());
//        List<AdamTagParentVo> existParentVos = this.getTagsForMusic().getData()
//                .stream().filter(r -> chooseTagMeParentVals.contains(r.getVal())).collect(Collectors.toList());
//        if (chooseTagMeParentVals.size() != existParentVos.size()) {
//            // 已选中的父级标签与系统筛选命中的父级标签数量不同
//            return ResponseDto.failure(ErrorMapping.get("10012"));
//        }
//        List<AdamTagParentVo> tagMeVoList = ObjectUtil.getAdamTagParentVoArrayList();
//        // tagMe子级标签校验处理
//        for (AdamTagParentVo parentVo : tagMeVos) {
//            // 系统对应的父级标签
//            AdamTagParentVo existParentVo = existParentVos.stream().filter(r -> r.getVal().equals(parentVo.getVal())).findAny().get();
//
//            List<AdamTagVo> tagVos = parentVo.getTagVos();
//
//            // TODO: 2021/6/13 第一版前端没有分级，暂不开启校验
//            if (CollectionUtils.isEmpty(tagVos)) {
//                existParentVo.setTagVos(null);
//                tagMeVoList.add(existParentVo);
//                continue;
//            }
//
//            List<AdamTagVo> allTagVos = existParentVo.getTagVos();
//
//            if (CollectionUtils.isEmpty(allTagVos) || tagVos.size() > allTagVos.size()) {
//                // 已选中的子级标签数量大于系统对应子级标签数量
//                return ResponseDto.failure(ErrorMapping.get("10012"));
//            }
//
//            // 已选中的子级标签key集合
//            List<String> chooseTagVoVals = tagVos.stream().map(AdamTagVo::getVal).collect(Collectors.toList());
//
//            List<AdamTagVo> existTagVos = allTagVos.stream().filter(r -> chooseTagVoVals.contains(r.getVal())).collect(Collectors.toList());
//            if (chooseTagVoVals.size() != existTagVos.size()) {
//                return ResponseDto.failure(ErrorMapping.get("10012"));
//            }
//            existParentVo.setTagVos(existTagVos);
//            tagMeVoList.add(existParentVo);
//        }
//        String currentUid = CurrentUtil.getCurrentUid();
//
//        AdamUserInfoVo editVo = adamRdmService.getUserInfoVoByUid(currentUid);
////        editVo.setAvatar(parameter.getAvatar());
////        editVo.setBackground(parameter.getBackground());
////        editVo.setNickname(parameter.getNickname());
//        editVo.setAvatar(StringUtils.isEmpty(editVo.getAvatar()) ? AdamConst.DEF_URL_AVATAR : editVo.getAvatar());
//        editVo.setBackground(StringUtils.isEmpty(editVo.getBackground()) ? AdamConst.DEF_URL_BACKGROUND : editVo.getBackground());
//        editVo.setNickname(editVo.getNickname());
//        editVo.setSex(sex);
//        editVo.setBirthday(parameter.getBirthday());
//        editVo.setArea(parameter.getArea());
////        editVo.setSignature(parameter.getSignature());
//        editVo.setSignature(editVo.getSignature());
////        editVo.setTagMe(tagMeVoList);
//        editVo.setUpdatedAt(LocalDateTime.now());
//        editVo.setIsComplete(1);
//
//        adamUserInfoService.edit(editVo);
////        editVo.setMobile(SensitizeUtil.custom(editVo.getMobile(), 3, 4));
//        return ResponseDto.success(editVo.desensitize(reviewUserInfo));
        parameter.setSex(sex);

        String currentUid = CurrentUtil.getCurrentUid();
        AdamUserInfoVo existUserInfoVo = adamRdmService.getUserInfoVoByUid(currentUid);

        String nickname = parameter.getNickname();
        if (StringUtils.isNotBlank(nickname) && !StringUtils.equals(existUserInfoVo.getNickname(), nickname)) {
            if (!shumeiUtil.checkText(currentUid, nickname)) {
                return ResponseDto.failure(ErrorMapping.get("10020"));
            }
        }
        String signature = parameter.getSignature();
        if (StringUtils.isNotBlank(signature) && !StringUtils.equals(existUserInfoVo.getSignature(), signature)) {
            if (!shumeiUtil.checkText(currentUid, signature)) {
                return ResponseDto.failure(ErrorMapping.get("10021"));
            }
        }
        String avatar = parameter.getAvatar();
        if (StringUtils.isNotBlank(avatar)) {
            if (!StringUtils.equals(existUserInfoVo.getAvatar(), avatar) && !StringUtils.equals(AdamConst.DEF_URL_AVATAR, avatar)) {
                if (!shumeiUtil.checkImage(currentUid, avatar)) {
                    return ResponseDto.failure(ErrorMapping.get("10022"));
                }
            }
        } else {
            parameter.setAvatar(AdamConst.DEF_URL_AVATAR);
        }
        String background = parameter.getBackground();
        if (StringUtils.isNotBlank(background)) {
            if (!StringUtils.equals(existUserInfoVo.getBackground(), background) && !StringUtils.equals(AdamConst.DEF_URL_BACKGROUND, background)) {
                if (!shumeiUtil.checkImage(currentUid, background)) {
                    return ResponseDto.failure(ErrorMapping.get("10023"));
                }
            }
        } else {
            parameter.setBackground(AdamConst.DEF_URL_BACKGROUND);
        }
        return adamUserInfoService.edit(existUserInfoVo, parameter);
    }

    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "音乐风格")
    @GetMapping(value = {"tag/ms"})
    public ResponseDto<List<AdamTagParentVo>> getTagsForMusic() {
        List<AdamTagParentVo> tagsForMusic = adamRdmService.getTagsForMusic();
        if (CollectionUtils.isEmpty(tagsForMusic)) {
            tagsForMusic = ObjectUtil.getAdamTagParentVoArrayList();
            tagsForMusic.add(AdamTagParentVo.getNew().setVal("MME01").setDesc("音乐人").setTagVos(Arrays.asList(
                    AdamTagParentVo.getNew().setVal("101").setDesc("A").setTagVos(Arrays.asList(
                            AdamTagParentVo.getNew().setVal("201001").setDesc("AA"),
                            AdamTagParentVo.getNew().setVal("201001").setDesc("AB")
                    )),
                    AdamTagParentVo.getNew().setVal("102").setDesc("B").setTagVos(Arrays.asList(
                            AdamTagParentVo.getNew().setVal("201001").setDesc("BA"),
                            AdamTagParentVo.getNew().setVal("201001").setDesc("BB")
                    )),
                    AdamTagParentVo.getNew().setVal("103").setDesc("C").setTagVos(Arrays.asList(
                            AdamTagParentVo.getNew().setVal("201001").setDesc("CA"),
                            AdamTagParentVo.getNew().setVal("201001").setDesc("CB")
                    ))
            )));
            tagsForMusic.add(AdamTagParentVo.getNew().setVal("MME02").setDesc("音乐风格").setTagVos(Arrays.asList(
                    AdamTagParentVo.getNew().setVal("201").setDesc("a").setTagVos(Arrays.asList(
                            AdamTagParentVo.getNew().setVal("201001").setDesc("aa"),
                            AdamTagParentVo.getNew().setVal("201002").setDesc("ab")
                    )),
                    AdamTagParentVo.getNew().setVal("202").setDesc("b").setTagVos(Arrays.asList(
                            AdamTagParentVo.getNew().setVal("202001").setDesc("ba"),
                            AdamTagParentVo.getNew().setVal("202002").setDesc("bb")
                    )),
                    AdamTagParentVo.getNew().setVal("203").setDesc("c").setTagVos(Arrays.asList(
                            AdamTagParentVo.getNew().setVal("203001").setDesc("ca"),
                            AdamTagParentVo.getNew().setVal("203002").setDesc("cb")
                    ))
            )));

            adamRdmService.setTagsForMusic(tagsForMusic);
        }
        return ResponseDto.success(tagsForMusic);
    }

    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "性别列表")
    @GetMapping(value = {"tag/sex"})
    public ResponseDto<List<AdamTagVo>> getTagsForSex() {
        List<AdamTagVo> tagsForSex = adamRdmService.getTagsForSex();
        if (CollectionUtils.isEmpty(tagsForSex)) {
            tagsForSex = ObjectUtil.getAdamTagVoArrayList();
            tagsForSex.add(AdamTagVo.getNew().setVal("MS00").setDesc("保密"));
            tagsForSex.add(AdamTagVo.getNew().setVal("MS01").setDesc("男性"));
            tagsForSex.add(AdamTagVo.getNew().setVal("MS02").setDesc("女性"));
//            tagsForSex.add(AdamTagVo.getNew().setVal("MS03").setDesc("跨性别女性"));
//            tagsForSex.add(AdamTagVo.getNew().setVal("MS04").setDesc("跨性别男性"));
//            tagsForSex.add(AdamTagVo.getNew().setVal("MS05").setDesc("双性别者"));
//            tagsForSex.add(AdamTagVo.getNew().setVal("MS06").setDesc("性别模糊"));
//            tagsForSex.add(AdamTagVo.getNew().setVal("MS07").setDesc("性别流动"));
//            tagsForSex.add(AdamTagVo.getNew().setVal("MS08").setDesc("无性别者"));
//            tagsForSex.add(AdamTagVo.getNew().setVal("MS09").setDesc("不确定性别"));
//            tagsForSex.add(AdamTagVo.getNew().setVal("MS10").setDesc("不在乎性别"));

            adamRdmService.setTagsForSex(tagsForSex);
        }
        return ResponseDto.success(tagsForSex);
    }

    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "手机号修改", notes = "手机号修改会刷新TOKEN，刷新后的TOKEN对应响应参数中[`data`]")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "mobile", value = "新手机号"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "code", value = "验证码", example = "111111"),
    })
    @PostMapping(value = {"edit/mobile"})
    public ResponseDto<String> editMobile(@Pattern(regexp = "\\d{11}", message = "手机号格式有误")
                                          @RequestParam String mobile,
                                          @Pattern(regexp = "\\d{6}", message = "验证码格式有误")
                                          @RequestParam String code) {
        log.debug("mobile:{},code:{}", mobile, code);

//        String currentUid = CurrentUtil.getCurrentUid();
//
//        String bindMobileExistUid = adamRdmService.getUidByMobile(mobile);
//        if (StringUtils.isNotEmpty(bindMobileExistUid)) {
//            return ResponseDto.failure(ErrorMapping.get("10009"));
//        }
//
//        ResponseDto<String> checkSmsCodeDto = this.checkSmsCode(mobile, code);
//        if (!checkSmsCodeDto.isSuccess()) return checkSmsCodeDto;
//
//        return ResponseDto.success(adamUserInfoService.editMobile(currentUid, mobile));
        return ResponseDto.failure(ErrorMapping.get("10027"));
    }

    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "实名认证")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "name", value = "姓名"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "idCard", value = "证件号"),
            @ApiImplicitParam(type = "form", required = false, dataType = "Integer", name = "beValid", value = "是否校验年满18周岁"),
    })
    @PostMapping(value = {"identity"})
    public ResponseDto<AdamRealInfoVo> identity(@RequestParam String name, @RequestParam String idCard, @RequestParam(required = false) Integer beValid) {
        log.debug("name:{},idCard:{}", name, idCard);
        if (!java.util.regex.Pattern.matches(LnsRegex.Valid.CN_HANZI, name)) {
            return ResponseDto.failure(ErrorMapping.get("10103"));
        }
        if (!java.util.regex.Pattern.matches(LnsRegex.Valid.CN_ID_CARD_REF, idCard)) {
            return ResponseDto.failure(ErrorMapping.get("10104"));
        }
        if (null != beValid && IDCardUtil.getAge(idCard) < 18) {
            return ResponseDto.failure(ErrorMapping.get("10100"));
        }
        String currentUid = CurrentUtil.getCurrentUid();
        AdamRealInfoVo realInfoVoByUid = adamRdmService.getRealInfoVoByUidPlain(currentUid);
        // 已实名：无论二要素(node=2)还是三要素(node=3)，都视为已完成实名，直接返回（避免重复实名/跨入口重复认证）
        if (null != realInfoVoByUid && realInfoVoByUid.getState() != null && realInfoVoByUid.getState() == 1) {
            realInfoVoByUid.setName(SensitizeUtil.chineseName(realInfoVoByUid.getName()));
            realInfoVoByUid.setIdCard(SensitizeUtil.custom(realInfoVoByUid.getIdCard(), 3, 2));
            return ResponseDto.success(realInfoVoByUid);
        }
        ResponseDto<AdamRealInfoVo> guard = guardIdCardNotBoundToOtherUid(currentUid, idCard);
        if (guard != null) {
            return guard;
        }
        AdamRealInfoVo vo = adamUserService.identityForUpsert(currentUid, name, idCard, (String) CurrentUtil.getTokenClaims().get(CurrentUtil.TOKEN_MOBILE), true);
        vo.setName(SensitizeUtil.chineseName(vo.getName()));
        vo.setIdCard(SensitizeUtil.custom(vo.getIdCard(), 3, 2));
        return ResponseDto.success(vo);
    }

//    @ApiOperationSupport(order = 6)
//    @ApiOperation(value = "密码修改")
//    @ApiImplicitParams({
//            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "mobile", value = "手机号"),
//            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "password", value = "密码"),
//            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "code", value = "验证码"),
//    })
//    @PostMapping(value = {"edit/pwd"})
//    public ResponseDto<Object> editPwd(@RequestParam String mobile, @RequestParam String password, @RequestParam String code) {
//        log.info("mobile:{},password:{},code:{}", mobile, password, code);
//
//
//
//        return ResponseDto.success();
//    }

    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "绑定第三方账号")
    @PostMapping(value = {"tpa/bind"})
    public ResponseDto<List<AdamThirdPartInfoVo>> bindTpa(@Valid @RequestBody AdamThirdPartParam parameter) {
        log.debug("login by tpa:{}", JsonUtils.toJson(parameter));

        String currentUid = CurrentUtil.getCurrentUid();

        String existUid = adamRdmService.getUidByPlatformOpenId(parameter.getPlatform(), parameter.getOpenId());
        if (StringUtils.isNotEmpty(existUid)) {
            if (existUid.equals(currentUid)) {
                return ResponseDto.success(adamRdmService.getThirdPartVoListByUid(currentUid));
            }
//            Boolean force = parameter.getForce();
//            if (null != force && force) {// 强制解绑，并重新绑定当前账号
//                adamUserService.bindTpaForce(currentUid, existUid, parameter);
//                return ResponseDto.success();
//            }
            return ResponseDto.failure(ErrorMapping.get("10007"));
        }

        // 判断该用户是否已绑定同类型第三方账号
        AdamThirdPartInfoVo bindThirdPartVo = adamRdmService.getThirdPartVoByUidPlatform(currentUid, parameter.getPlatform());
        if (null != bindThirdPartVo) return ResponseDto.failure(ErrorMapping.get("10008"));

        adamUserService.bindTpa(currentUid, parameter);

        return ResponseDto.success(adamRdmService.getThirdPartVoListByUid(currentUid));
    }

    @ApiOperationSupport(order = 8)
    @ApiOperation(value = "解绑第三方账号")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "platform", value = "平台类型", allowableValues = "WEIBO,WECHAT,QQ"),
    })
    @PostMapping(value = {"tpa/unbind/{platform}"})
    public ResponseDto<List<AdamThirdPartInfoVo>> unbindTpa(@Pattern(regexp = LnsRegex.Valid.TRIPLE_PF_FOR_ULGOIN, message = "平台类型无效")
                                                            @PathVariable String platform) {
        String currentUid = CurrentUtil.getCurrentUid();
        log.debug("unbind tpa.platform:{},uid:{}", platform, currentUid);

        adamUserService.unBindTpa(currentUid, platform);

        return ResponseDto.success(adamRdmService.getThirdPartVoListByUid(currentUid));
    }

//    @ApiOperationSupport(order = 9)
//    @ApiOperation(value = "个人信息")
//    @PostMapping(value = {"info"})
//    public ResponseDto<Map<String, Object>> info() {
//        String currentUid = CurrentUtil.getCurrentUid();
//
//        Map<String, Object> map = CollectionUtil.mapStringObject();
//        AdamUserInfoVo userInfoVo = adamRdmService.getUserInfoVoByUid(currentUid);
//        map.put("realNameInfo", adamRdmService.getRealInfoVoByUid(currentUid));
//        map.put("thirdPartInfo", adamRdmService.getThirdPartVoListByUid(currentUid));
//        AdamUserMemberVo userMemberVo = adamRdmService.getUserMemberVoByUid(currentUid);
//        map.put("userMemberVo", userMemberVo);
//        map.put("userInfo", adamRdmService.ratingProvince(userInfoVo).desensitize(reviewUserInfo).rating(userMemberVo));
//        map.put("memberVo", adamRdmService.getMemberSimpleVo());
//
//        return ResponseDto.success(map);
//    }
    @ApiOperationSupport(order = 9)
    @ApiOperation(value = "个人信息")
    @PostMapping(value = {"info"})
    public ResponseDto<AdamUserProfileVo> info() {
        String currentUid = CurrentUtil.getCurrentUid();
        AdamUserProfileVo userProfileVo = AdamUserProfileVo.getNew();

        AdamUserInfoVo userInfoVo = adamRdmService.getUserInfoVoByUid(currentUid);
        if (null == userInfoVo) {
            log.warn("###用户不存在[UID:{},TOKEN:{}]", currentUid, CurrentUtil.getToken());
            return ResponseDto.success(userProfileVo);
        }

        userProfileVo.setRealNameInfo(adamRdmService.getRealInfoVoByUid(currentUid));

        userProfileVo.setThirdPartInfo(adamRdmService.getThirdPartVoListByUid(currentUid));

        userProfileVo.setMemberVo(adamRdmService.getMemberSimpleVo());

        AdamUserMemberVo userMemberVo = adamRdmService.getUserMemberVoByUid(currentUid);
        userProfileVo.setUserMemberVo(userMemberVo);

        userProfileVo.setUserInfo(adamRdmService.ratingProvince(userInfoVo).desensitize(reviewUserInfo).rating(userMemberVo));

//        userProfileVo.setBizAcctVoList(adamRdmService.getBizAcctVosByUid(currentUid));

        AdamMemberJoinusVo memberJoinusVo;
        if (org.springframework.util.StringUtils.startsWithIgnoreCase(userInfoVo.getQrCode(), "lN")) {
            memberJoinusVo = adamRdmService.getMemberJoinusVo(0);
        } else {
            memberJoinusVo = adamRdmService.getMemberJoinusVo(null != userMemberVo && userMemberVo.isActive() ? 50 : 10);
            memberJoinusVo.setState(1);
            memberJoinusVo.setQrCode(userInfoVo.getQrCode());
            if (null != userMemberVo) {
                memberJoinusVo.setMemberNo(userMemberVo.getMemberNo());
            }
        }
        userProfileVo.setMemberJoinusVo(memberJoinusVo);

        AdamNftVo adamNftVo = AdamNftVo.getNew();
        adamNftVo.setHasNft(adamRdmService.hasNft(currentUid) ? 1 : 2);
        adamNftVo.setHasNftOrder(adamRdmService.hasNftOrder(currentUid) ? 1 : 2);
        userProfileVo.setAdamNftVo(adamNftVo);

        return ResponseDto.success(userProfileVo);
    }

    @ApiOperationSupport(order = 10)
    @ApiOperation(value = "用户简易信息", notes = "根据用户手机号查询用户姓名，id，手机号")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "mobile", value = "手机号"),
    })
    @PostMapping(value = {"gif/mobile"})
    public ResponseDto<AdamUserInfoSimpleVo> getInfoByMobile(@Pattern(regexp = "\\d{11}", message = "手机号格式有误")
                                                             @RequestParam(name = "mobile", required = false) String mobile) {
        String uid;
        if (mobile != null) {
            uid = adamRdmService.getUidByMobile(mobile);
        } else {
            uid = CurrentUtil.getCurrentUid();
        }
        AdamUserInfoVo userInfoVo;
        if (uid == null || null == (userInfoVo = adamRdmService.getUserInfoVoByUid(uid))) {
            log.warn("###用户不存在[MOBILE:{},UID:{},TOKEN:{}]", mobile, uid, CurrentUtil.getToken());
            return ResponseDto.failure("账号不存在，请确认");
        }
        AdamUserInfoSimpleVo vo = AdamUserInfoSimpleVo.getNew();
        if (userInfoVo.getState().equals(1)) {
            vo.setMobile(userInfoVo.getMobile());
            vo.setUid(userInfoVo.getUid());
            vo.setNickname(userInfoVo.getNickname());
            vo.setAvatar(userInfoVo.getAvatar());
            return ResponseDto.success(vo);
        } else {
            return ResponseDto.failure("账号不存在，请确认");
        }
    }

    @ApiOperationSupport(order = 11)
    @ApiOperation(value = "用户身份信息")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "mobile", value = "手机号"),
    })
    @GetMapping(value = "info/identity")
    public ResponseDto<AdamUserIdentityInfoVo> identityInfoByMobile(@Pattern(regexp = "\\d{11}", message = "手机号格式有误")
                                                                    @RequestParam(required = false) String mobile) {
        String uid = null == mobile ? CurrentUtil.getCurrentUid() : adamRdmService.getUidByMobile(mobile);
        if (uid == null) {
            log.warn("###用户不存在[mobile:{},uid:{},token:{}]", mobile, uid, CurrentUtil.getToken());
            return ResponseDto.failure(ErrorMapping.get("10114"));
        }
        return this.identityInfoByUID(uid);
    }

    @ApiOperationSupport(order = 12)
    @ApiOperation(value = "用户身份信息")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "id", value = "手机号"),
    })
    @GetMapping(value = "info/identity2")
    public ResponseDto<AdamUserIdentityInfoVo> identityInfoByUID(@RequestParam(required = false) String id) {
        String uid = StringUtils.isBlank(id) ? CurrentUtil.getCurrentUid() : id;
        AdamUserInfoVo userInfoVo;
        if (uid == null || null == (userInfoVo = adamRdmService.getUserInfoVoByUid(uid))) {
            log.warn("###用户不存在[id:{},uid:{},token:{}]", id, uid, CurrentUtil.getToken());
            return ResponseDto.failure(ErrorMapping.get("10114"));
        }
        AdamRealInfoVo realInfoVoByUidPlain = adamRdmService.getRealInfoVoByUidPlain(uid);
        // 已实名：兼容二要素(node=2) 与 三要素(node=3)，统一以 state=1 为准
        if (null == realInfoVoByUidPlain || realInfoVoByUidPlain.getState() == null || realInfoVoByUidPlain.getState() != 1) {
            return ResponseDto.failure(ErrorMapping.get("10115"));
        }
        AdamUserIdentityInfoVo userIdentityInfoVo = AdamUserIdentityInfoVo.getNew();
        userIdentityInfoVo.setUid(uid);
        userIdentityInfoVo.setName(realInfoVoByUidPlain.getName());
        userIdentityInfoVo.setMobile(userInfoVo.getMobile());
        return ResponseDto.success(userIdentityInfoVo.desensitize());
    }

    @ApiOperationSupport(order = 13)
    @ApiOperation(value = "验证手机号")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "mobile", value = "手机号[用于验证当前账户所绑定手机号]"),
    })
    @PostMapping(value = {"check/mobile"})
    public ResponseDto<Object> checkMobile(@NotBlank(message = "手机号不能为空") @Pattern(regexp = "\\d{11}", message = "手机号格式有误") @RequestParam String mobile) {
        String currentMobile = (String) CurrentUtil.getTokenClaims().get(CurrentUtil.TOKEN_MOBILE);
        return mobile.equals(currentMobile) ? ResponseDto.success() : ResponseDto.failure(ErrorMapping.get("10003"));
    }


    @ApiOperationSupport(order = 14)
    @ApiOperation(value = "通过Uid获取用户信息VO")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "uid", value = "Uid[用户ID]"),
    })
    @GetMapping(value = {"info/rds"})
    public ResponseDto<AdamUserInfoVo> getAdamUserInfoByUid(@NotBlank(message = "Uid不能为空") @RequestParam(value = "uid") String uid) {
        return ResponseDto.success(adamRdmService.getUserInfoVoByUid(uid));
    }


    @ApiOperationSupport(order = 15)
    @ApiOperation(value = "实名认证V2（二要素）", notes = "支持手动填写(name+idCard) 或 选择观演人(entersId)")
    @PostMapping(value = {"identity/v2"})
    public ResponseDto<AdamRealInfoVo> identityV2(@RequestBody AdamIdentityParam param) {
        String currentUid = CurrentUtil.getCurrentUid();

        // 1. 检查当前登录用户是否已实名
        AdamRealInfoVo realInfoVo = adamRdmService.getRealInfoVoByUidPlain(currentUid);
        if (realInfoVo != null && realInfoVo.getState() != null && realInfoVo.getState() == 1) {
            // 已实名，直接返回
            realInfoVo.setName(SensitizeUtil.chineseName(realInfoVo.getName()));
            realInfoVo.setIdCard(SensitizeUtil.custom(realInfoVo.getIdCard(), 3, 2));
            return ResponseDto.success(realInfoVo);
        }

        String name = param.getName();
        String idCard = param.getIdCard();

        // 2. 如果传了 entersId，则根据 entersId 获取观演人的姓名和身份证号
        if (StringUtils.isNotBlank(param.getEntersId())) {
            List<AdamEntersVo> entersList = adamRdmService.getEntersVoByUid(currentUid);
            if (!CollectionUtils.isEmpty(entersList)) {
                AdamEntersVo entersVo = entersList.stream()
                        .filter(e -> param.getEntersId().equals(e.getEntersId()))
                        .findFirst()
                        .orElse(null);
                if (entersVo == null) {
                    return ResponseDto.failure(ErrorMapping.get("10105")); // 观演人不存在
                }
                // 只同步身份证类型的观演人信息 (type=1 大陆身份证)
                if (entersVo.getType() == null || entersVo.getType() != 1) {
                    return ResponseDto.failure("10101", "仅支持大陆身份证类型的观演人进行实名认证");
                }
                name = entersVo.getName();
                idCard = entersVo.getIdCard();
            } else {
                return ResponseDto.failure(ErrorMapping.get("10105")); // 观演人不存在
            }
        }

        // 3. 校验姓名和身份证号不能为空
        if (StringUtils.isBlank(name) || StringUtils.isBlank(idCard)) {
            return ResponseDto.failure(ErrorMapping.get("10101")); // 姓名或身份证件号无效
        }

        // 4. 格式校验
        if (!java.util.regex.Pattern.matches(LnsRegex.Valid.CN_HANZI, name)) {
            return ResponseDto.failure(ErrorMapping.get("10103"));
        }
        if (!java.util.regex.Pattern.matches(LnsRegex.Valid.CN_ID_CARD_REF, idCard)) {
            return ResponseDto.failure(ErrorMapping.get("10104"));
        }

        ResponseDto<AdamRealInfoVo> guard = guardIdCardNotBoundToOtherUid(currentUid, idCard);
        if (guard != null) {
            return guard;
        }
        AdamRealInfoVo vo = adamUserService.verifyTwoElements(currentUid, name, idCard);
        if (null == vo) {
            log.error("[identityV2] 二要素认证失败, param: {}", JsonUtils.toJson(param));
            return ResponseDto.failure(ErrorMapping.get("10101"));
        }
        vo.setName(SensitizeUtil.chineseName(vo.getName()));
        vo.setIdCard(SensitizeUtil.custom(vo.getIdCard(), 3, 2));
        return ResponseDto.success(vo);

    }

    /**
     * 同一个身份证号（state=1）只能绑定一个账号。
     * 放在 controller 层：对所有实名入口统一拦截，返回明确错误码给前端。
     */
    private ResponseDto<AdamRealInfoVo> guardIdCardNotBoundToOtherUid(String uid, String idCard) {
        if (StringUtils.isBlank(uid) || StringUtils.isBlank(idCard)) {
            return null;
        }
        String boundUid = adamRdmService.getRealNameBoundUidByIdCard(idCard);
        if (StringUtils.isNotBlank(boundUid) && !uid.equals(boundUid)) {
            return ResponseDto.failure(ErrorMapping.get("10614"));
        }
        return null;
    }

    /* ---------------------------- Internal Method ---------------------------- */

    private static final String PHP_API_SMS_CODE_VALID = "/smsValidation";

    private ResponseDto<String> checkSmsCode(String mobile, String code) {
        if (!LnsEnum.ENV.prod.name().equals(env.getProperty(CurrentUtil.CK_ENV_ACTIVE))
                && CurrentUtil.GRAY_LOGIN_SMS_CODE.equals(code)) {
            return ResponseDto.success();
        }

        String smsCodeByMobile = adamRdmService.getSmsCodeByMobile(mobile);
        if (null == smsCodeByMobile) {
            return ResponseDto.failure(ErrorMapping.get("10004"));
        }
        return smsCodeByMobile.equals(code) ? ResponseDto.success() : ResponseDto.failure(ErrorMapping.get("10004"));
    }
}
