package com.ruoyi.web.modules.account.service.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.framework.web.service.UserDetailsServiceImpl;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.modules.account.constant.MemberConstants;
import com.ruoyi.web.modules.account.domain.BizMember;
import com.ruoyi.web.modules.account.dto.MemberChangePasswordDTO;
import com.ruoyi.web.modules.account.dto.MemberCreateDTO;
import com.ruoyi.web.modules.account.dto.MemberLoginDTO;
import com.ruoyi.web.modules.account.dto.MemberProfileUpdateDTO;
import com.ruoyi.web.modules.account.dto.MemberRegisterDTO;
import com.ruoyi.web.modules.account.facade.IMemberFacade;
import com.ruoyi.web.modules.account.mapper.BizMemberMapper;
import com.ruoyi.web.modules.account.service.IMemberAppService;
import com.ruoyi.web.modules.account.service.IMemberSmsService;
import com.ruoyi.web.modules.account.support.MemberAvatarSupport;
import com.ruoyi.web.modules.account.support.MemberRegistrationSupport;
import com.ruoyi.web.modules.account.vo.MemberProfileAppVO;
import com.ruoyi.web.modules.content.facade.IMallServiceAgreementFacade;
import com.ruoyi.web.modules.pay.support.WeChatPaySupport;

/**
 * C 端会员 Service 实现
 */
@Service
public class MemberAppServiceImpl implements IMemberAppService
{
    private static final Pattern MOBILE_PATTERN = Pattern.compile("^1\\d{10}$");

    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[\\w.-]+@[\\w.-]+\\.\\w+$");

    @Autowired
    private BizMemberMapper memberMapper;

    @Autowired
    private IMemberSmsService smsService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private IMallServiceAgreementFacade mallServiceAgreementFacade;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private MemberRegistrationSupport memberRegistrationSupport;

    @Autowired
    private MemberAvatarSupport memberAvatarSupport;

    @Autowired
    private IMemberFacade memberFacade;

    @Autowired
    private WeChatPaySupport weChatPaySupport;

    @Override
    public void sendSms(String mobile)
    {
        smsService.sendCode(mobile);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long register(MemberRegisterDTO dto)
    {
        validateRegister(dto);
        mallServiceAgreementFacade.assertAcceptedForRegister(Boolean.TRUE.equals(dto.getAgreementAccepted()));
        if (memberMapper.countByMobile(dto.getMobile(), null) > 0)
        {
            throw new ServiceException("手机号已注册");
        }

        MemberCreateDTO create = new MemberCreateDTO();
        create.setMobile(dto.getMobile());
        create.setPassword(dto.getPassword());
        create.setMemberCode(dto.getMemberCode());
        create.setNickName(dto.getNickName());
        create.setAvatar(memberAvatarSupport.resolve(null));
        return memberRegistrationSupport.createMember(create, "member");
    }

    @Override
    public Map<String, Object> login(MemberLoginDTO dto)
    {
        String account = resolveLoginAccount(dto);
        if (dto == null || StringUtils.isEmpty(account) || StringUtils.isEmpty(dto.getPassword()))
        {
            throw new ServiceException("请输入账号和密码");
        }
        mallServiceAgreementFacade.assertAcceptedForLogin(Boolean.TRUE.equals(dto.getAgreementAccepted()));
        BizMember member = resolveMemberByAccount(account);
        if (member == null)
        {
            throw new ServiceException("账号或密码错误");
        }
        if (!MemberConstants.STATUS_ENABLED.equals(member.getStatus()))
        {
            throw new ServiceException("账号已禁用，请联系客服");
        }
        if (!SecurityUtils.matchesPassword(dto.getPassword(), member.getPassword()))
        {
            throw new ServiceException("账号或密码错误");
        }
        SysUser user = sysUserService.selectUserById(member.getMemberId());
        if (user == null)
        {
            throw new ServiceException("账号或密码错误");
        }
        LoginUser loginUser = (LoginUser) userDetailsService.createLoginUser(user);
        recordLoginInfo(user.getUserId());
        String token = tokenService.createToken(loginUser);
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("memberId", member.getMemberId());
        return result;
    }

    @Override
    public MemberProfileAppVO getProfile(Long memberId)
    {
        BizMember member = requireMember(memberId);
        return toProfileVo(member);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProfile(Long memberId, MemberProfileUpdateDTO dto)
    {
        requireMember(memberId);
        if (dto == null)
        {
            throw new ServiceException("参数不能为空");
        }
        if (StringUtils.isEmpty(dto.getNickName()))
        {
            throw new ServiceException("请输入昵称");
        }
        validateEmail(dto.getEmail());
        validateSex(dto.getSex());

        BizMember accountUpdate = new BizMember();
        accountUpdate.setMemberId(memberId);
        accountUpdate.setUpdateBy(String.valueOf(memberId));
        accountUpdate.setNickName(dto.getNickName().trim());
        accountUpdate.setAvatar(dto.getAvatar());
        accountUpdate.setEmail(dto.getEmail());
        accountUpdate.setSex(dto.getSex());
        memberMapper.updateAccount(accountUpdate);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changePassword(Long memberId, MemberChangePasswordDTO dto)
    {
        BizMember member = requireMember(memberId);
        if (dto == null || StringUtils.isEmpty(dto.getOldPassword()) || StringUtils.isEmpty(dto.getNewPassword())
                || StringUtils.isEmpty(dto.getConfirmPassword()))
        {
            throw new ServiceException("请完整填写密码信息");
        }
        if (!dto.getNewPassword().equals(dto.getConfirmPassword()))
        {
            throw new ServiceException("两次输入的密码不一致");
        }
        if (!SecurityUtils.matchesPassword(dto.getOldPassword(), member.getPassword()))
        {
            throw new ServiceException("旧密码错误");
        }

        BizMember accountUpdate = new BizMember();
        accountUpdate.setMemberId(memberId);
        accountUpdate.setUpdateBy(String.valueOf(memberId));
        accountUpdate.setPassword(SecurityUtils.encryptPassword(dto.getNewPassword()));
        memberMapper.updateAccount(accountUpdate);
    }

    private BizMember requireMember(Long memberId)
    {
        BizMember member = memberMapper.selectById(memberId);
        if (member == null)
        {
            throw new ServiceException("会员不存在");
        }
        return member;
    }

    private MemberProfileAppVO toProfileVo(BizMember member)
    {
        MemberProfileAppVO vo = new MemberProfileAppVO();
        vo.setMemberId(member.getMemberId());
        vo.setMobile(member.getMobile());
        vo.setMemberCode(member.getMemberCode());
        vo.setNickName(member.getNickName());
        vo.setAvatar(memberAvatarSupport.resolve(member.getAvatar()));
        vo.setEmail(member.getEmail());
        vo.setSex(member.getSex());
        return vo;
    }

    private void validateEmail(String email)
    {
        if (StringUtils.isEmpty(email))
        {
            return;
        }
        if (!EMAIL_PATTERN.matcher(email.trim()).matches())
        {
            throw new ServiceException("邮箱格式不正确");
        }
    }

    private void validateSex(String sex)
    {
        if (StringUtils.isEmpty(sex))
        {
            return;
        }
        if (!"0".equals(sex) && !"1".equals(sex) && !"2".equals(sex))
        {
            throw new ServiceException("性别参数不正确");
        }
    }

    private String resolveLoginAccount(MemberLoginDTO dto)
    {
        if (dto == null)
        {
            return null;
        }
        if (StringUtils.isNotEmpty(dto.getAccount()))
        {
            return dto.getAccount().trim();
        }
        if (StringUtils.isNotEmpty(dto.getMobile()))
        {
            return dto.getMobile().trim();
        }
        return null;
    }

    private BizMember resolveMemberByAccount(String account)
    {
        if (MOBILE_PATTERN.matcher(account).matches())
        {
            return memberMapper.selectByMobile(account);
        }
        return memberMapper.selectByMemberCode(account);
    }

    /** 与 {@link com.ruoyi.framework.web.service.SysLoginService#recordLoginInfo} 一致，无 Web 上下文时跳过 */
    private void recordLoginInfo(Long userId)
    {
        if (ServletUtils.getRequestAttributes() != null)
        {
            sysUserService.updateLoginInfo(userId, IpUtils.getIpAddr(), DateUtils.getNowDate());
        }
    }

    private void validateRegister(MemberRegisterDTO dto)
    {
        if (dto == null || StringUtils.isEmpty(dto.getMobile()))
        {
            throw new ServiceException("请输入手机号");
        }
        if (StringUtils.isEmpty(dto.getPassword()))
        {
            throw new ServiceException("请输入密码");
        }
        if (StringUtils.isEmpty(dto.getConfirmPassword()))
        {
            throw new ServiceException("请输入确认密码");
        }
        if (!dto.getPassword().equals(dto.getConfirmPassword()))
        {
            throw new ServiceException("两次输入的密码不一致");
        }
    }

    @Override
    public void bindWxOpenid(Long memberId, String code)
    {
        String openid = weChatPaySupport.resolveOpenidByCode(code);
        memberFacade.bindWxOpenid(memberId, openid);
    }
}
