package shop.alien.storeplatform.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.alibaba.fastjson.JSONObject;
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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import shop.alien.config.redis.BaseRedisService;
import shop.alien.entity.result.R;
import shop.alien.entity.store.StoreInfo;
import shop.alien.entity.store.StoreUser;
import shop.alien.entity.store.vo.StoreUserVo;
import shop.alien.mapper.StoreInfoMapper;
import shop.alien.mapper.StoreUserMapper;
import shop.alien.storeplatform.service.StorePlatformLoginervice;
import shop.alien.util.common.DateUtils;
import shop.alien.util.common.JwtUtil;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
@RefreshScope
public class StorePlatformLoginServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser> implements StorePlatformLoginervice {

    @Value("${jwt.expiration-time}")
    private String effectiveTime;

    @Value("${captcha.register.timeOut}")
    private Long timeOut;

    private final StoreUserMapper storeUserMapper;
    private final StoreInfoMapper storeInfoMapper;
    private final BaseRedisService baseRedisService;

    @Override
    public R<Boolean> register(String phone, String password) {
        try {
            LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(StoreUser::getPhone, phone)
                    .orderByDesc(StoreUser::getCreatedTime).last("LIMIT 1");
            StoreUser storeUser = storeUserMapper.selectOne(queryWrapper);

            List<Integer> noRegister = Arrays.asList(0, 1);

            if (Objects.isNull((storeUser))) {
                // 没有数据
                saveNewUser(phone, password);
                return R.success("操作成功");

            } else if (noRegister.contains(storeUser.getStatus())) {
                return R.fail("手机号已经注册过");
            }

            int daysSinceDeletion = DateUtils.subtraction(storeUser.getCreatedTime(), new Date());
            if (daysSinceDeletion < 30) return R.fail(String.format("请于%d天后重新申请注册", 30 - daysSinceDeletion));
            saveNewUser(phone, password);
            return R.success("操作成功");
        } catch (Exception e) {
            log.error("StorePlatformLoginServiceImpl.register(): Error Msg={}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    private void saveNewUser(String phone, String password) {
        StoreUser registerStoreUser = new StoreUser();
        registerStoreUser.setPhone(phone);
        registerStoreUser.setPassword(password);
        registerStoreUser.setMoney(0);
        registerStoreUser.setDeleteFlag(0);
        registerStoreUser.setStatus(0);
        registerStoreUser.setPassType(2);
        registerStoreUser.setCreatedTime(new Date());
        registerStoreUser.setLogoutFlag(0);
        registerStoreUser.setNickName(phone);
        storeUserMapper.insert(registerStoreUser);
    }

    @Override
    public boolean checkRegister(String phone) {
        try {
            LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(StoreUser::getPhone, phone);
            queryWrapper.in(StoreUser::getStatus, 0, 1);
            List<StoreUser> storeUsers = storeUserMapper.selectList(queryWrapper);
            return CollectionUtils.isEmpty(storeUsers) ? Boolean.TRUE : Boolean.FALSE;
        } catch (Exception e) {
            log.error("StorePlatformLoginServiceImpl.checkRegister(): Error Msg={}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public R<StoreUserVo> createToKen(StoreUser storeUser) {
        try {
            int effectiveTimeInt = Integer.parseInt(effectiveTime.substring(0, effectiveTime.length() - 1));
            String effectiveTimeUnit = effectiveTime.substring(effectiveTime.length() - 1);
            long effectiveTimeIntLong = 0L;
            switch (effectiveTimeUnit) {
                case "s": {
                    effectiveTimeIntLong = effectiveTimeInt * 1000L;
                    break;
                }
                case "m": {
                    effectiveTimeIntLong = effectiveTimeInt * 60L * 1000L;
                    break;
                }
                case "h": {
                    effectiveTimeIntLong = effectiveTimeInt * 60L * 60L * 1000L;
                    break;
                }
                case "d": {
                    effectiveTimeIntLong = effectiveTimeInt * 24L * 60L * 60L * 1000L;
                    break;
                }
            }

            StoreUserVo storeUserVo = new StoreUserVo();
            BeanUtils.copyProperties(storeUser, storeUserVo);
            Map<String, String> tokenMap = new HashMap<>();
            tokenMap.put("phone", storeUser.getPhone());
            tokenMap.put("userName", storeUser.getName());
            tokenMap.put("userId", storeUser.getId().toString());
            tokenMap.put("userType", "storePlatform");
            storeUserVo.setToken(JwtUtil.createJWT("storePlatform_" + storeUser.getPhone(), storeUser.getName(), JSONObject.toJSONString(tokenMap), effectiveTimeIntLong));
            baseRedisService.setString("storePlatform_" + storeUser.getPhone(), storeUserVo.getToken());
            StoreInfo storeInfo = storeInfoMapper.selectById(storeUser.getStoreId());
            if (storeInfo != null) {
                storeUserVo.setBusinessSection(storeInfo.getBusinessSection());
                storeUserVo.setBusinessTypesName(storeInfo.getBusinessTypesName());
                storeUserVo.setMealsFlag(storeInfo.getMealsFlag());
                storeUserVo.setStoreTickets(storeInfo.getStoreTickets());

            }
            return R.data(storeUserVo);
        } catch (Exception e) {
            log.error("StorePlatformLoginServiceImpl.createToKen(): Error Msg={}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public R<String> forgetOrModifyPassword(String phone, String newPhone, String oldPassword, String newPassword, String confirmNewPassword, String verificationCode, Integer type) {
        boolean flag = false;
        try {
            //类型为0 忘记密码
            if (type == 0) {
                return forgetPassword(phone, newPassword);
            }
            //修改密码
            else if (type == 1) {
                //效验新密码规则
                passwordVerification(phone, oldPassword, newPassword, confirmNewPassword);
                LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(StoreUser::getPhone, phone);
                updateWrapper.set(StoreUser::getPassword, newPassword);
                flag = this.update(updateWrapper);

                //修改成功后同步删除redis缓存token
                if (flag) {
                    String token = "store_platform_" + phone;
                    String toKenStr = baseRedisService.getString(token);
                    if (toKenStr != null) {
                        baseRedisService.delete(token);
                    }
                    return R.success("密码修改成功");
                } else {
                    log.error("密码修改失败");
                    return R.fail("密码修改失败");
                }
            }
            //更换绑定手机号
            else if (type == 2) {
                return ChangeBoundPhone(phone, newPhone);
            }
            return R.success("密码修改成功");
        } catch (Exception e) {
            log.info("StorePlatformLoginServiceImpl.forgetOrModifyPassword(): Error Msg={}", e.getMessage());
            return R.fail(e.getMessage());
        }
    }

    @Override
    public void generateCaptcha(HttpServletResponse response, HttpSession session) throws IOException {
        try {
            LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100, 4, 100);
            session.setAttribute("captcha", captcha.getCode());
            response.setContentType("image/png");
            response.setHeader("Pragma", "No-cache");
            captcha.write(response.getOutputStream());
        } catch (IOException e) {
            log.error("StorePlatformLoginServiceImpl.generateCaptcha(): Error Msg={}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public JSONObject getExpirationTime(Integer storeId) throws Exception {
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("expirationTime", 1);
            jsonObject.put("foodLicenceExpirationTime", 1);
            jsonObject.put("entertainmentLicenceExpirationTime", 1);

            StoreInfo storeInfo = storeInfoMapper.selectById(storeId);
            if (storeInfo != null) {
                if (storeInfo.getExpirationTime() == null || storeInfo.getExpirationTime().compareTo(new Date()) < 0) {
                    jsonObject.put("expirationTime", 0);
                }
                if (storeInfo.getFoodLicenceExpirationTime() == null || storeInfo.getFoodLicenceExpirationTime().compareTo(new Date()) < 0) {
                    jsonObject.put("foodLicenceExpirationTime", 0);
                }
                if (storeInfo.getEntertainmentLicenceExpirationTime() != null && storeInfo.getEntertainmentLicenceExpirationTime().compareTo(new Date()) < 0) {
                    jsonObject.put("entertainmentLicenceExpirationTime", 0);
                }
            }
            return jsonObject;
        } catch (Exception e) {
            log.error("StorePlatformLoginServiceImpl.getExpirationTime(): Error Msg={}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    private void passwordVerification(String phone, String password, String newPassword, String confirmNewPassword) {
        LambdaUpdateWrapper<StoreUser> wrapperFans = new LambdaUpdateWrapper<>();
        wrapperFans.eq(StoreUser::getPhone, phone);
        StoreUser storeUser = this.getOne(wrapperFans);
        if (!newPassword.equals(confirmNewPassword)) {
            log.info("两次新密码输入不一致 请重新输入");
            throw new RuntimeException("两次新密码输入不一致 请重新输入");
        }
        if (storeUser == null || storeUser.equals("")) {
            log.info("该手机号没有注册过账户");
            throw new RuntimeException("该手机号没有注册过账户");
        } else {
            wrapperFans.eq(StoreUser::getPassword, password);
            StoreUser storeUserPw = this.getOne(wrapperFans);
            if (storeUserPw == null || storeUserPw.getPassword().equals("")) {
                log.info("原密码错误");
                throw new RuntimeException("原密码错误");
            }
        }
    }

    private R<String> forgetPassword(String phone, String newPassword) {
        boolean flag = false;
        LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StoreUser::getPhone, phone);
        updateWrapper.set(StoreUser::getPassword, newPassword);
        flag = this.update(updateWrapper);
        if (flag) {
            log.info("密码修改成功");
            String token = "store_platform_" + phone;
            String tokenStr = baseRedisService.getString(token);
            if (tokenStr != null) {
                baseRedisService.delete(token);
            }
        }
        if (!flag) {
            log.error("密码修改失败");
            throw new RuntimeException("密码修改失败");
        }
        return R.success("密码修改成功");
    }

    private R<String> ChangeBoundPhone(String phone, String newPhone) {
        boolean flag = false;
        //获取新手机号验证码
        LambdaUpdateWrapper<StoreUser> newUpdateWrapper = new LambdaUpdateWrapper<>();
        newUpdateWrapper.eq(StoreUser::getPhone, newPhone);
        StoreUser newStoreUser = this.getOne(newUpdateWrapper);
        if (newStoreUser != null) {
            if (newStoreUser.getPhone().equals(newPhone)) {
                throw new RuntimeException("该手机号已注册过商户");
            }
        } else {
            LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(StoreUser::getPhone, phone);
            StoreUser storeUser = this.getOne(updateWrapper);
            storeUser.setPhone(newPhone);
            flag = this.updateById(storeUser);
            if (flag) {
                String token = "store_platform_" + phone;
                String tokenStr = baseRedisService.getString(token);
                if (tokenStr != null) {
                    baseRedisService.delete(token);
                }
            }
        }
        return R.success("新手机号绑定成功");
    }

}
