package com.sdtool.business.service.mall;

import com.sdtool.business.dao.MallDao;
import com.sdtool.common.api.ConfigService;
import com.sdtool.common.api.ImagePuzzleCaptcha;
import com.sdtool.common.api.NoSqlKeysService;
import com.sdtool.common.api.mall.MallFrontService;
import com.sdtool.common.base.BaseService;
import com.sdtool.common.datas.HttpCode;
import com.sdtool.common.datas.RedisKeys;
import com.sdtool.common.datas.TokenUserFrom;
import com.sdtool.common.entity.base.InvokeCallParams;
import com.sdtool.common.entity.base.InvokeCallResult;
import com.sdtool.common.entity.base.ProcessStringItem;
import com.sdtool.common.entity.mall.MallUser;
import com.sdtool.common.entity.site.ERPTokenUser;
import com.sdtool.common.entity.system.AuthCode;
import com.sdtool.common.entity.system.ConfigValue;
import com.sdtool.common.tool.AliSmsService;
import com.sdtool.common.tool.ERPUtils;
import com.dySweetFishPlugin.redis.RedisService;
import com.dySweetFishPlugin.sql.TableIdService;
import com.dySweetFishPlugin.sql.dao.TunaService;
import com.dySweetFishPlugin.tool.crypto.EncryptUtil;
import com.sweetfish.service.Local;
import com.sweetfish.service.RetResult;
import com.sweetfish.util.AnyValue;
import com.sweetfish.util.AutoLoad;
import com.sweetfish.util.ResourceType;
import org.apache.commons.lang3.StringUtils;
import org.rex.RMap;

import javax.annotation.Resource;
import java.time.Instant;
import java.util.Date;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @Author: xl Created on 2024-03-26
 * @Content:
 */
@Local
@AutoLoad(false)
@ResourceType(MallFrontService.class)
public class MallFrontServiceImpl extends BaseService implements MallFrontService {

    @Resource
    ImagePuzzleCaptcha imagePuzzleCaptcha;

    @Resource
    RedisService redisService;

    @Resource
    NoSqlKeysService keysService;

    @Resource
    AliSmsService aliSmsService;

    @Resource
    TunaService tunaService;

    @Resource
    TableIdService tableIdService;

    @Resource
    ConfigService configService;

    @Resource(name = "property.passwordSalt")
    private String passwordSalt;

    private MallDao mallDao;

    public void start(AnyValue config) {
        mallDao = tunaService.generate(MallDao.class);
    }

    @Override
    public RetResult<InvokeCallResult> callMall(InvokeCallParams source, Boolean needLogin, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
        if (needLogin) {
            if (currentUser == null) {
                return RetResult.<InvokeCallResult>errorT().retcode(HttpCode.UNAUTHORIZED.value()).retinfo("未登录");
            }
        }

        if (source == null) {
            return RetResult.<InvokeCallResult>errorT().retinfo("无效的参数信息");
        }

        if (StringUtils.isEmpty(source.getBusinessMethod())) {
            return RetResult.<InvokeCallResult>errorT().retinfo("无效的参数方法[businessMethod]信息");
        }

        source.setCurrentUser(currentUser);
        source.setDataSourceId(dataSourceId);
        source.setSupplierCode(supplierCode);

        return callScript(source.getBusinessMethod(), source, currentUser, dataSourceId, supplierCode);
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    public int accountExists(String loginAccount, String dataSourceId, long supplierCode) {
        //先查redis
        if (redisService.exists(keysService.getRedisKey(RedisKeys.KEY_ACCOUNT_MALL_CHECK, supplierCode, true) + loginAccount)) {
            return 1;
        }

        //查询数据库
        RMap paramMap = new RMap();
        paramMap.put("loginAccount", loginAccount);
        long count = mallDao.accountExists(paramMap, dataSourceId, supplierCode);
        if (count > 0L) {
            //如果账号存在，则在redis里面存储5分钟
            redisService.setex(keysService.getRedisKey(RedisKeys.KEY_ACCOUNT_MALL_CHECK, supplierCode, true) + loginAccount, 5 * 60, loginAccount);
            return 1;
        } else {
            return 0;
        }
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    public long accountId(String loginAccount, String dataSourceId, long supplierCode) {
        //查询数据库
        RMap paramMap = new RMap();
        paramMap.put("loginAccount", loginAccount);
        return mallDao.accountId(paramMap, dataSourceId, supplierCode);
    }

    @Override
    public RetResult<MallUser> registerMallUser(MallUser registerUser, String sessionId, int locationX, String smsCode,
                                                String dataSourceId, long supplierCode) {

        String locationSrcStr = redisService.get(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true) + "register:" + sessionId);
        if (StringUtils.isEmpty(locationSrcStr)) {
            return RetResult.<MallUser>errorT().retinfo("请点击按钮进行验证");
        }

        int locationSrc = Integer.parseInt(locationSrcStr);
        if ((locationX > locationSrc + 4) || (locationX < locationSrc - 4)) {
            //验证不通过
            return RetResult.<MallUser>errorT().retinfo("验证失败，请重新验证");
        }

        //短信验证码判断
        if (StringUtils.isEmpty(smsCode)) {
            return RetResult.<MallUser>errorT().retinfo("请输入短信验证码");
        }

        String smsSrc = redisService.get(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true) + "registersms" + ":" + registerUser.getLoginAccount());
        if (StringUtils.isEmpty(smsSrc)) {
            return RetResult.<MallUser>errorT().retinfo("请获取短信验证码进行验证");
        }

        if (!smsCode.equalsIgnoreCase(smsSrc)) {
            return RetResult.<MallUser>errorT().retinfo("短信验证码输入错误");
        }

        if (StringUtils.isBlank(registerUser.getLoginAccount())) {
            return RetResult.<MallUser>errorT().retinfo("账号不可为空");
        }

        if (StringUtils.isBlank(registerUser.getPassword())) {
            return RetResult.<MallUser>errorT().retinfo("请设置登陆密码");
        }

        if (StringUtils.isBlank(registerUser.getUserName())) {
            return RetResult.<MallUser>errorT().retinfo("请填写客户名称");
        }

        if (StringUtils.equalsIgnoreCase("admin", registerUser.getUserName())) {
            return RetResult.<MallUser>errorT().retinfo("客户名称不合法，请重新输入");
        }

        int iExists = this.accountExists(registerUser.getLoginAccount(), dataSourceId, supplierCode);
        if (iExists == 1) {
            RetResult.<MallUser>errorT().retinfo("账号已存在");
        }

        ConfigValue verifyConfig = configService.getRedisConfigValue("MallUserVerify", dataSourceId, supplierCode);

        registerUser.setId(tableIdService.getTableIdMulti("tbUser.id", 1, dataSourceId, String.valueOf(supplierCode)));
        registerUser.setLoginName(registerUser.getUserName());
        registerUser.setPassword(EncryptUtil.md5Digest(registerUser.getPassword() + passwordSalt));
        registerUser.setVoidFlag(0);
        registerUser.setLevelExpireDateLong(0L);
        registerUser.setLevelExpireDate(null);
        registerUser.setIdLevel(0L);

        if ((verifyConfig == null) || (verifyConfig.getConfigValue1().equalsIgnoreCase("0"))) {
            registerUser.setVerifyFlag(1);
            registerUser.setIdVerifyUser(ERPUtils.getSysTokenUser().getId());
            registerUser.setVerifyUser(ERPUtils.getSysTokenUser().getUserName());
            registerUser.setVerifyDate(Date.from(Instant.now()));
            registerUser.setVerifyDateLong(registerUser.getVerifyDate().getTime());
        } else {
            registerUser.setVerifyFlag(0);
            registerUser.setIdVerifyUser(0L);
            registerUser.setVerifyUser("");
            registerUser.setVerifyDate(null);
            registerUser.setVerifyDateLong(0L);
        }

        MallUser.create(registerUser, registerUser.getId());

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_ERP_MALL_User, supplierCode), String.valueOf(registerUser.getId()), registerUser);
        mallDao.addMallLoginUser(registerUser, dataSourceId, supplierCode);

        return RetResult.successT();
    }

    @Override
    public RetResult<AuthCode> generateAuthCode(String sessionId, String authName, TokenUserFrom userFrom, String dataSourceId, long supplierCode) {
        AuthCode authCode = imagePuzzleCaptcha.generateCaptchaImage();
        if (authCode != null) {
            if (authCode.getStatus() != 0) {
                return RetResult.<AuthCode>errorT().retinfo("验证码刷新频繁，请稍后刷新");
            }
            //设置5分钟过期
            redisService.setex(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true) + authName + ":" + sessionId, 5 * 60, authCode.getLocationX());
            authCode.setLocationX(-1);

            authCode.setSourceImage("/apis" + userFrom.getValue() + "/SourceCaptchaImage/" + authCode.getSourceImage());
            authCode.setBigImgage("/apis" + userFrom.getValue() + "/VerifyCaptchaImage/" + authCode.getBigImgage());
            authCode.setXyImage("/apis" + userFrom.getValue() + "/VerifyCaptchaImage/" + authCode.getXyImage());


            return RetResult.<AuthCode>successT().result(authCode);
        } else {
            return RetResult.<AuthCode>errorT().retinfo("请求验证码出错");
        }
    }

    @Override
    public RetResult<ProcessStringItem> checkPuzzleX(String sessionId, String authName, int locationX, String dataSourceId, long supplierCode) {
        if (locationX < 0) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请点击按钮进行验证");
        }

        String locationSrcStr = redisService.get(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true) + authName + ":" + sessionId);
        if (StringUtils.isEmpty(locationSrcStr)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请点击按钮进行验证");
        }

        int locationSrc = Integer.parseInt(locationSrcStr);
        if ((locationX > locationSrc + 4) || (locationX < locationSrc - 4)) {
            //验证不通过
            return RetResult.<ProcessStringItem>errorT().retinfo("验证失败，请重新验证");
        }

        return RetResult.successT();
    }

    @Override
    public RetResult<ProcessStringItem> regSendSms(String sessionId, String phoneNo, int locationX, String dataSourceId, long supplierCode) {
        if (locationX < 0) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请点击按钮进行验证");
        }

        if (StringUtils.isEmpty(phoneNo)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("手机号未输入");
        }

        String locationSrcStr = redisService.get(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true) + "register:" + sessionId);
        if (StringUtils.isEmpty(locationSrcStr)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请点击按钮进行验证");
        }

        int locationSrc = Integer.parseInt(locationSrcStr);
        if ((locationX > locationSrc + 4) || (locationX < locationSrc - 4)) {
            //验证不通过
            return RetResult.<ProcessStringItem>errorT().retinfo("验证失败，请重新验证");
        }

        //检查登录账号是否重复
        int iExists = accountExists(phoneNo, dataSourceId, supplierCode);
        if (iExists == 1) {
            return RetResult.<ProcessStringItem>errorT().retinfo("手机号已注册，请重新输入");
        }

        String regSmsCode = String.valueOf(ThreadLocalRandom.current().nextInt(10000, 100000));
        //boolean sms = smsService.sendRegisterSMS(phoneNo, new String[]{regSmsCode});
        boolean sms = aliSmsService.sendRegisterSMS(phoneNo, regSmsCode);
        if (sms) {
            //存到缓存中进行验证
            redisService.setex(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true)
                    + "registersms" + ":" + phoneNo, 5 * 60, regSmsCode);
            return RetResult.successT();
        } else {
            return RetResult.<ProcessStringItem>errorT().retinfo("发送验证码出错");
        }
    }

    @Override
    public RetResult<ProcessStringItem> fwdSendSms(String sessionId, String phoneNo, int locationX, String dataSourceId, long supplierCode) {
        if (locationX < 0) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请点击按钮进行验证");
        }

        if (StringUtils.isEmpty(phoneNo)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("手机号未输入");
        }

        String locationSrcStr = redisService.get(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true) + "fwd:" + sessionId);
        if (StringUtils.isEmpty(locationSrcStr)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请点击按钮进行验证");
        }

        int locationSrc = Integer.parseInt(locationSrcStr);
        if ((locationX > locationSrc + 4) || (locationX < locationSrc - 4)) {
            //验证不通过
            return RetResult.<ProcessStringItem>errorT().retinfo("验证失败，请重新验证");
        }

        //检查登录账号是否存在
        int iExists = accountExists(phoneNo, dataSourceId, supplierCode);

        if (iExists == 0) {
            return RetResult.<ProcessStringItem>errorT().retinfo("手机号不存在，请重新输入");
        }

        String fwdSmsCode = String.valueOf(ThreadLocalRandom.current().nextInt(10000, 100000));
        //boolean sms = smsService.sendRegisterSMS(phoneNo, new String[]{fwdSmsCode});
        boolean sms = aliSmsService.sendRegisterSMS(phoneNo, fwdSmsCode);
        if (sms) {
            //存到缓存中进行验证
            redisService.setex(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true)
                    + "fwdsms" + ":" + phoneNo, 5 * 60, fwdSmsCode);

            return RetResult.successT();
        } else {
            return RetResult.<ProcessStringItem>errorT().retinfo("发送验证码出错");
        }
    }

    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public RetResult<ProcessStringItem> fwdPassword(String account, String sessionId, int locationX, String smsCode, String dataSourceId, long supplierCode) {
        if (StringUtils.isBlank(account)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请输入有效的账号");
        }

        //拼图验证码判断
        String locationSrcStr = redisService.get(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true) + "fwd:" + sessionId);
        if (StringUtils.isBlank(locationSrcStr)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请点击按钮进行验证");
        }

        int locationSrc = Integer.parseInt(locationSrcStr);
        if ((locationX > locationSrc + 4) || (locationX < locationSrc - 4)) {
            //验证不通过
            return RetResult.<ProcessStringItem>errorT().retinfo("验证失败，请重新验证");
        }

        //短信验证码判断
        if (StringUtils.isBlank(smsCode)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请输入短信验证码");
        }

        String smsSrc = redisService.get(keysService.getRedisKey(RedisKeys.KEY_AUTHCODE, supplierCode, true) + "fwdsms" + ":" + account);
        if (StringUtils.isBlank(smsSrc)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("请获取短信验证码进行验证");
        }

        if (!smsCode.equals(smsSrc)) {
            return RetResult.<ProcessStringItem>errorT().retinfo("短信验证码输入错误");
        }

        RMap paramMap = new RMap();
        paramMap.put("linkedAccount", account);
        paramMap.put("linkedPassword", EncryptUtil.md5Digest(account + passwordSalt));
        mallDao.resetMallUserPassword(paramMap, dataSourceId, supplierCode);

        return RetResult.<ProcessStringItem>successT().result(
                ProcessStringItem.newBuilder()
                        .itemValue("登录密码重置，默认和账号相同，请登录后及时进行修")
                        .build()
        );
    }
}
