package com.sv.service.api;

import com.enums.MemberStatusEnum;
import com.enums.MoneyLogEnum;
import com.enums.PayTypeEnum;
import com.github.pagehelper.PageHelper;
import com.sv.dto.api.InformationDTO;
import com.sv.dto.api.MemberDTO;
import com.sv.entity.Member;
import com.sv.entity.MemberFaceInfo;
import com.sv.exception.FaceServiceException;
import com.sv.exception.api.ExceptionCodeTemplate;
import com.sv.mapper.MemberMapper;
import com.sv.service.common.ApiConstants;
import com.sv.service.common.CaptchaCacheServiceImpl;
import com.sv.service.common.FaceService;
import com.sv.service.common.OSSClientUtil;
import com.ydd.framework.core.common.Pagination;
import com.ydd.framework.core.common.utils.ValidationUtils;
import com.ydd.framework.core.entity.enums.DeletedEnum;
import com.ydd.framework.core.entity.enums.StatusEnum;
import com.ydd.framework.core.exception.ServiceException;
import com.ydd.framework.core.interceptor.AccessTokenInterceptor;
import com.ydd.framework.core.service.CacheService;
import com.ydd.framework.core.service.impl.BaseServiceImpl;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Service - 用户
 *
 * @author zhaoziyu
 * @since 2018-08-01
 */
@Service("MemberServiceApi")
@Transactional
public class MemberService extends BaseServiceImpl {

    private final Logger logger = LoggerFactory.getLogger(MemberService.class);

    @Resource
    private MemberMapper memberMapper;

    @Resource
    private CacheService cacheService;

    @Resource
    private OSSClientUtil ossClientUtil;

    @Resource
    private FaceService faceService;
    @Resource
    private CaptchaCacheServiceImpl captchaCacheService;
    @Resource
    private MemberService memberService;
    @Resource
    private MemberWithdrawApplyService memberWithdrawApplyService;
    @Resource
    private MemberMoneyLogService memberMoneyLogService;
    @Resource
    private MemberAuthService memberAuthService;

    /**
     * 创建用户
     *
     * @param member 用户
     */

    @Transactional
    public void save(Member member) {
        if (member.getId() != null && member.getId() > 0) {
            // 更新
            memberMapper.update(member);
        } else {
            // 新建
            memberMapper.insert(member);
        }
    }

    /**
     * 更新用户
     *
     * @param member 用户
     */

    @Transactional
    public void update(Member member) {
        memberMapper.update(member);
    }

    /**
     * 删除用户
     *
     * @param id 编号
     * @return 删除数量
     */

    @Transactional
    public Integer delete(Integer id) {
        if (id == null || id <= 0) {
            return 0;
        }
        return memberMapper.delete(id);
    }

    /**
     * 删除用户
     *
     * @param ids 编号数组
     * @return 删除数量
     */

    @Transactional
    public Integer deleteByIds(Integer[] ids) {
        if (ids == null || ids.length == 0) {
            return 0;
        }
        return memberMapper.deleteByIds(ids);
    }

    /**
     * 后台接口引用
     * 查询用户人脸
     *
     * @param id 编号
     * @return
     */
    public Member findByIds(Integer id) {
        return memberMapper.findByIds(id);
    }

    /**
     * api接口引用
     * <p>
     * 查询用户
     *
     * @param id 编号
     * @return 用户
     */
    public Member findById(Integer id) {
        return memberMapper.findById(id);
    }

    /**
     * api
     */
    public Member findByMember(Integer id) {
        return memberMapper.findByMember(id);
    }

    /**
     * 查询用户
     *
     * @param pagination 分页信息
     * @return 分页结果
     */

    public Pagination findPage(Pagination pagination) {
        PageHelper.startPage(pagination.getPage(), pagination.getPageSize());
        PageHelper.orderBy("id desc");
        pagination.setQueryResult(memberMapper.findAll());
        return pagination;
    }

    /**
     * 更新状态
     *
     * @param ids    编号
     * @param status 状态
     * @return 更新数量
     */

    @Transactional
    public Integer updateStatus(Integer[] ids, Byte status) {
        if (ids == null) {
            return 0;
        }
        if (status == null) {
            status = StatusEnum.DISABLE.value;
        }

        return memberMapper.updateStatus(ids, status);
    }

    /**
     * 手机号码是否存在
     *
     * @param mobile    手机号码
     * @param excludeId 排除编号
     * @return 存在返回 {@code true}，反之 {@code false}
     */
    public Boolean isMobileExists(String mobile, Integer excludeId) {
        return memberMapper.countByMobile(mobile, excludeId) != 0;
    }

    /**
     * 创建新用户
     *
     * @param mobile 手机号码
     * @return 新用户
     */
    @Transactional
    public Member createByMobile(String mobile, String name, Integer sex, Integer age, String address, Integer platformId) {
        // 参数校验
        ValidationUtils.assertNotNull(mobile);
        ValidationUtils.assertMobile(mobile);

        // 验证手机号码是否存在
        assertMobileNotUsed(mobile, null);

        // 创建用户
        Member member = new Member();
        member.setNickname(mobile);
        String inviteCode = "";
        Integer count = 1;
        while (count == 1) {
            inviteCode = RandomStringUtils.randomNumeric(10);
            count = memberMapper.checkInviteCode(inviteCode);
        }
        member.setInviteCode(inviteCode);
        member.setMobile(mobile);
        if (name != null) {
            if (name.length() > 8) {
                throw new ServiceException("姓名不能超过8位");
            }
            member.setName(name);
        }
        if (sex != null) {
            member.setSex(sex);
        }
        if (age != null) {
            if (age.intValue() < 10 || age.intValue() > 100) {
                throw new ServiceException("年龄在10-100之间");
            }
            member.setAge(age);
        }
        if (address != null) {
            member.setAddress(address);
        }
        member.setPlatformId(platformId);
        memberMapper.insert(member);
        return member;
    }

    /**
     * 断言手机号码未使用
     *
     * @param mobile    手机号码
     * @param excludeId 排除编号
     */
    public void assertMobileNotUsed(String mobile, Integer excludeId) {
        // 验证手机号码是否存在
        if (isMobileExists(mobile, excludeId)) {
            throw new ServiceException(ExceptionCodeTemplate.MOBILE_EXISTS);
        }
    }

    /**
     * 根据手机号码查找用户
     */
    public Member findByMobile(String mobile) {
        return memberMapper.findByMobile(mobile);
    }

    /**
     * 查询用户状态
     *
     * @param id
     * @return
     */
    public Member findAndVerifyById(Integer id) {
        return verify(findById(id));
    }

    public Member verify(Member member) {
        if (member == null || DeletedEnum.YES.value.equals(member.getDeleted())) {
            throw new ServiceException(ExceptionCodeTemplate.NONE_MEMBER_INFORMATION);
        }
        if (member.getStatus().intValue() == MemberStatusEnum.DISABLE.value.intValue()) {
            throw new ServiceException(ExceptionCodeTemplate.MEMBER_ERROR);
        }
        return member;
    }

    /**
     * 检查用户公益课黑名单状态
     * 0正常 1 公益课黑名单
     *
     * @param member
     */
    public void verifyMemberBanType(Member member) {
        if (new Integer(1).equals(member.getBanType())) {
            throw new ServiceException(ExceptionCodeTemplate.MEMBER_HAD_BANED);
        }
    }

    /**
     * 通过accessToken获取用户ID
     *
     * @param accessToken
     * @return
     */
    public Integer getMemberIdByAccessToken(String accessToken) {
        Integer id = cacheService.getEntity(AccessTokenInterceptor.ACCESS_TOKEN_CACHE_KEY + accessToken);
        if (id == null)
            throw new ServiceException(com.ydd.framework.core.exception.ExceptionCodeTemplate.INVALID_ACCESS_TOKEN);
        boolean flag = checkMemberValid(id);
        if (!flag) {
            throw new ServiceException(ExceptionCodeTemplate.MEMBER_IN_VALID);
        }
        return id;
    }

    private boolean checkMemberValid(Integer memberId) {
        Member member = memberMapper.findById(memberId);
        if (member == null)
            throw new ServiceException(com.ydd.framework.core.exception.ExceptionCodeTemplate.INVALID_ACCESS_TOKEN);
        if (member.getStatus().intValue() == 1) {
            //用户已经被封禁
            return false;
        }
        return true;
    }

    /**
     * 修改用户余额
     */
    @Transactional
    public void updateMoney(Integer memberId, BigDecimal price) {
        memberMapper.updateMoney(memberId, price);
    }

    /**
     * 用户中心查询
     *
     * @param memberId
     * @return
     */
    public Member center(Integer memberId) {
        if (memberId == null) {
            throw new ServiceException(com.ydd.framework.core.exception.ExceptionCodeTemplate.NEED_LOGIN);
        }
        Member member = memberMapper.findByMember(memberId);
        verify(member);
        return member;
    }

    /**
     * 个人信息
     */
    public MemberDTO information(Integer memberId) {
        if (memberId == null) {
            throw new ServiceException(com.ydd.framework.core.exception.ExceptionCodeTemplate.NEED_LOGIN);
        }
        Member member = memberMapper.findById(memberId);
        verify(member);
        MemberDTO memberDTO = new MemberDTO();
        memberDTO.setId(member.getId());
        memberDTO.setAvatar(member.getAvatar() == null ? "" : member.getAvatar());
        memberDTO.setNickname(member.getNickname());
        memberDTO.setMobile(member.getMobile());
        memberDTO.setName(member.getName() == null ? "" : member.getName());
        memberDTO.setSex(member.getSex());
        memberDTO.setAge(member.getAge() == null ? null : member.getAge());
        memberDTO.setAddress(member.getAddress() == null ? "" : member.getAddress());
        return memberDTO;
    }

    /**
     * 修改个人信息
     */
    public void updateInformation(Integer memberId, InformationDTO informationDTO) {
        Member member = memberMapper.findById(memberId);
        verify(member); // 验证用户信息

        String regEx = "[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]|\n|\r|\t";
        Pattern pattern = Pattern.compile(regEx);

        if (informationDTO.getName() != null) {
            Matcher matcher = pattern.matcher(informationDTO.getName());
            if (matcher.find()) {
                throw new ServiceException("姓名不能包含特殊字符");
            }
            if (informationDTO.getName().length() > 8) {
                throw new ServiceException("姓名不能超过8位");
            }
            member.setName(informationDTO.getName());
        }

        if (informationDTO.getAge() != null) {
            if ((Integer.valueOf(informationDTO.getAge()).intValue() < 10 || Integer.valueOf(informationDTO.getAge()).intValue() > 100)) {
                throw new ServiceException("年龄在10-100之间");
            }
        }
        if (informationDTO.getNickname() == null && informationDTO.getSex() == null && informationDTO.getAddress() == null && informationDTO.getName() == null) {
            member.setAge(informationDTO.getAge());
        }

        if (informationDTO.getNickname() != null) {
            if ("".equals(informationDTO.getNickname())) {
                throw new ServiceException("昵称不能为空");
            }
            Matcher matcher = pattern.matcher(informationDTO.getNickname());
            if (matcher.find()) {
                throw new ServiceException("昵称不能包含特殊字符");
            }
            if (informationDTO.getNickname().length() > 8) {
                throw new ServiceException("昵称不能超过8位");
            }
            member.setNickname(informationDTO.getNickname());
        }

        if (informationDTO.getSex() != null) {
            member.setSex(informationDTO.getSex());
        }
        if (informationDTO.getAddress() != null) {
            Matcher matcher = pattern.matcher(informationDTO.getAddress());
            if (matcher.find()) {
                throw new ServiceException("地址不能包含特殊字符");
            }
            member.setAddress(informationDTO.getAddress());
        }

        if (informationDTO.getMobile() != null) {
            ValidationUtils.assertMobile(informationDTO.getMobile()); // 校验手机号码格式
            ValidationUtils.assertNotNull(informationDTO.getCaptcha()); // 验证码不能为空
            // 校验验证码是否正确
            captchaCacheService.assertCaptcha(informationDTO.getMobile(), ApiConstants.UPDATE_PHONE_SMS_CAPTCHA_PREFIX, informationDTO.getCaptcha());

            //修改电话号码，需要判断用户表中是否已经存在
            if (isMobileExists(informationDTO.getMobile(), memberId)) {
                // 手机号码已存在
                throw new ServiceException("手机号已存在");
            } else {
                member.setMobile(informationDTO.getMobile());
                // 同时修改登陆表中的手机号,通过用户ID
                memberAuthService.updateMobile(informationDTO.getMobile(), memberId);

            }
        }

        memberMapper.update(member);
    }

    /**
     * 设置用户的face信息
     *
     * @param subjectId
     * @param faceUrl
     * @param memberId
     */
    public void setMemberFaceInfo(Integer subjectId, String faceUrl, Integer memberId, Integer platformId) {
        MemberFaceInfo memberFaceInfo = memberMapper.findMemberFaceInfo(memberId);
        if (memberFaceInfo == null) {
            memberFaceInfo = new MemberFaceInfo();
            memberFaceInfo.setMemberId(memberId);
            memberFaceInfo.setPlatformId(platformId);
        }
        memberFaceInfo.setFaceId(subjectId);
        memberFaceInfo.setFaceUrl(faceUrl);
        memberFaceInfo.setModifiedTime(new Date());
        if (memberFaceInfo.getId() == null) {
            memberMapper.insertMemberFaceInfo(memberFaceInfo);
        } else {
            memberMapper.updateMemberFaceInfo(memberFaceInfo);
        }
    }

    /**
     * 上传用户人脸识别头像
     *
     * @param memberId
     * @param file
     */
    @Transactional
    public void setMemberFaceInfo(Integer memberId, MultipartFile file, Integer platformId) {
        Date now = new Date();
        MemberFaceInfo memberFaceInfo = memberMapper.findMemberFaceInfo(memberId);
        if (memberFaceInfo != null) {
            //判断上次修改日期 如果小于30天不允许修改
            if ((now.getTime() - memberFaceInfo.getModifiedTime().getTime()) <= (30 * 24 * 60 * 60 * 1000)) {
                throw new ServiceException("人脸照片只允许30天设置一次");
            }
        }
        synchronized (("face" + memberId).intern()) {
            try {
                byte[] byt = new byte[file.getInputStream().available()];
                file.getInputStream().read(byt);
                Member member = memberMapper.findById(memberId);
                if (member != null) {
                    String imgUrl = ossClientUtil.uploadImg(new ByteArrayInputStream(byt), file.getOriginalFilename());
                    faceService.login();
                    Integer faceId = faceService.uploadFace(new ByteArrayInputStream(byt));
                    Integer subjectId = faceService.addSubject(faceId, member);
                    logger.info(faceId + "&&" + subjectId);
                    if (memberFaceInfo != null) {
                        //删除原有的subject
                        faceService.deleteSubject(memberFaceInfo.getFaceId());
                    }
                    setMemberFaceInfo(subjectId, imgUrl, memberId, platformId);
                }
            } catch (FaceServiceException e) {
                e.printStackTrace();
                throw new ServiceException(e.getMessage());
            } catch (Exception e) {
                logger.info("unknown error",e);
                throw new ServiceException("设置人脸失败，请稍后再试");
            }
        }
    }

    /**
     * 通过人脸识别的faceID获取用户
     *
     * @param faceId
     * @return
     */
    public Member findByFaceId(Integer faceId) {
        return memberMapper.findByFaceId(faceId);
    }

    /**
     * 查看用户余额是否足够扣款
     *
     * @param memberId
     * @param price
     * @return
     */
    public boolean isMoneyEnough(Integer memberId, BigDecimal price) {
        return memberMapper.countMoneyGtPrice(memberId, price) > 0;
    }

    /**
     * 提现申请
     */
    public void withdrawApply(BigDecimal money, Integer memberId, Integer bankId, Integer platformId) {
        // 判断用户是否登录
        if (memberId == null) {
            throw new ServiceException(com.ydd.framework.core.exception.ExceptionCodeTemplate.NEED_LOGIN);
        }
        Member member = memberService.findById(memberId);
        memberService.verify(member);
        //参数校验
        ValidationUtils.assertNotNull(money);
        ValidationUtils.assertNotNull(bankId, "请选择银行卡");
        if (money.compareTo(new BigDecimal(0)) != 1) {
            throw new ServiceException("提现金额不能少于0");
        }
        if (money.compareTo(member.getMoney()) == 1) {
            throw new ServiceException(ExceptionCodeTemplate.MONEY_ERROR);
        }

        // 金额保留2位小数
        money = money.setScale(2);

        // 1. 生成‘用户提现申请’记录
        memberWithdrawApplyService.create(memberId, bankId, money, platformId);
        // 2. 生成‘用户账单（余额，微信，会员卡）记录’3.扣除用户的余额
        memberMoneyLogService.create(memberId, platformId, MoneyLogEnum.APPLY_MONEY.value, money.multiply(new BigDecimal(-1)), PayTypeEnum.BALANCE.value, null, null, null, null);
    }

    /**
     * 修改用户的黑名单状态
     * @param memberId
     * @param stauts
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateMemberBanStatus(Integer memberId,Integer stauts){
        Member member = new Member();
        member.setId(memberId);
        member.setStatus(stauts);
        memberMapper.updateBanStatus(member);
    }
}

