package com.fdkankan.ucenter.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fdkankan.common.constant.ConstantRegex;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.util.*;
import com.fdkankan.fyun.face.FYunFileServiceInterface;
import com.fdkankan.image.MatrixToImageWriterUtil;
import com.fdkankan.sign.AesUtil;
import com.fdkankan.sms.SmsService;
import com.fdkankan.ucenter.common.MailUtil;
import com.fdkankan.ucenter.common.constants.ConstantFilePath;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.util.RedisUtil;
import com.fdkankan.ucenter.common.RedisKeyUtil;
import com.fdkankan.ucenter.common.constants.NacosProperty;
import com.fdkankan.ucenter.config.UcenterConfig;
import com.fdkankan.ucenter.constant.LoginConstant;
import com.fdkankan.ucenter.constant.QrCodeFilePath;
import com.fdkankan.ucenter.entity.Camera;
import com.fdkankan.ucenter.entity.CameraDetail;
import com.fdkankan.ucenter.entity.User;
import com.fdkankan.ucenter.service.*;
import com.fdkankan.ucenter.vo.request.LoginParam;
import com.fdkankan.ucenter.vo.request.RegisterParam;
import com.fdkankan.ucenter.vo.response.LoginVo;
import com.fdkankan.ucenter.vo.response.UserVo;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import io.netty.util.internal.UnstableApi;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;


@Service
public class LoginService {

    @Autowired
    private IUserService userService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SmsService smsService;
    @Autowired
    private ICameraService cameraService;
    @Autowired
    private ICameraDetailService cameraDetailService;
    @Autowired
    private ILoginLogService loginLogService;
    @Value("${sms.template.verification-code}")
    private String cnCode;
    @Value("${admin.register.validCode:2a22bac40f44af4d3b5fdc20ea706fc5}")
    private String registerValidCode;
    @Autowired
    private FYunFileServiceInterface fYunFileServiceInterface;
    @Autowired
    private IMailTemplateService mailTemplateService;
    @Autowired
    UcenterConfig ucenterConfig;
    @Autowired
    ISceneCooperationService sceneCooperationService;


    public LoginVo login(User user){
        String token = this.redisLogin(user.getUserName(),JSONObject.toJSONString(user),"user");
        loginLogService.addLog("",token);
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user,userVo);
        LoginVo vo = new LoginVo();
        vo.setToken(token);
        vo.setUser(userVo);
        return vo;
    }

    public LoginVo login(LoginParam param) {
        if (StringUtils.isEmpty(param.getPassword()) || StringUtils.isEmpty(param.getPhoneNum())){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        String password ;
        if(StringUtils.isNotBlank(param.getClear()) && param.getClear().equals("YES")){
            try {
                String desEncrypt = AesUtil.desEncrypt(param.getPassword());
                password = desEncrypt;
            }catch (Exception e){
                throw new BusinessException(LoginConstant.FAILURE_CODE_3014, LoginConstant.FAILURE_MSG_3014);
            }
        }else {
            password = Base64Converter.decode(Base64Converter.subText(param.getPassword()));
        }
        String passwordCode = SecurityUtil.MD5(password);
        User user = userService.getByUserName(param.getPhoneNum());
        if(user == null){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3015, LoginConstant.FAILURE_MSG_3015);
        }
        if(!user.getPassword().equals(passwordCode)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3014, LoginConstant.FAILURE_MSG_3014);
        }
        return login(user);
    }

    public void logout(String token) {
        String redisKey = String.format(RedisKey.TOKEN_V3,token);
        if(redisUtil.hasKey(redisKey)){
            redisUtil.del(redisKey);
        }
    }

    public void checkUser(String phoneNum,Boolean flg) {
        if(StringUtils.isBlank(phoneNum)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        User user = userService.getByUserName(phoneNum);
        if(user == null && flg){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3015, LoginConstant.FAILURE_MSG_3015);
        }
        if(user != null && !flg){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3008, LoginConstant.FAILURE_MSG_3008);
        }
    }

    public void getMsgAuthCode(String areaNum, String phoneNum) {
        String redisKeyTime = RedisKeyUtil.PREFIX_MSG_NOT_CODE + phoneNum;      //重发验证
        String redisKeyMsg = RedisKeyUtil.PREFIX_MSG_AUTH_CODE + phoneNum;      //验证码code

        long value =  redisUtil.getExpire(redisKeyTime);
        if(value != -2){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3033, String.valueOf(value));
        }
        String code = String.valueOf((int)((Math.random()*9+1)*100000));
        if(StringUtils.isBlank(areaNum)){
            areaNum = "86";
        }
        if ("86".equals(areaNum)){
            String sendCode = null;
            try {
                sendCode = smsService.sendSms(phoneNum, "{\"code\":\"" + code + "\"}", cnCode);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if("isv.BUSINESS_LIMIT_CONTROL".equals(sendCode)){
                throw new BusinessException(LoginConstant.FAILURE_CODE_3023, LoginConstant.FAILURE_MSG_3023);
            }
        }else{
            try{
                smsService.sendSMSMessage(areaNum + phoneNum, code);
            }catch (Exception e){
                e.printStackTrace();
                throw new BusinessException(LoginConstant.FAILURE_CODE_3013, LoginConstant.FAILURE_MSG_3013);
            }
        }
        if(redisUtil.hasKey(redisKeyMsg)){
            redisUtil.del(redisKeyMsg);
        }
        redisUtil.set(redisKeyMsg,code,300);
        redisUtil.set(redisKeyTime,String.valueOf(new Date().getTime()),60);
    }

    public void register(RegisterParam param) {
        if (StringUtils.isEmpty(param.getPassword()) || StringUtils.isEmpty(param.getPhoneNum()) ||
                StringUtils.isEmpty(param.getMsgAuthCode())
                || StringUtils.isEmpty(param.getConfirmPwd())){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        if(StringUtils.isBlank(param.getCountry())){
            param.setCountry("86");
        }
        String password ;
        if(StringUtils.isNotBlank(param.getClear()) && param.getClear().equals("YES")){
            try {
                password = AesUtil.desEncrypt(param.getPassword());
            } catch (Exception e) {
                throw new BusinessException(LoginConstant.FAILURE_CODE_3014, LoginConstant.FAILURE_MSG_3014);
            }
        }else {
            password = Base64Converter.decode(Base64Converter.subText(param.getPassword()));
        }
        if(!password.matches(ConstantFilePath.PASSWORD_REGEX)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3011, LoginConstant.FAILURE_MSG_3011);
        }
        if (!param.getConfirmPwd().equals(param.getPassword())){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3009, LoginConstant.FAILURE_MSG_3009);
        }
        if(!param.getMsgAuthCode().equals(registerValidCode)){
            checkSms(param.getMsgAuthCode(),param.getPhoneNum(),true);
        }
        User user = userService.getByUserName(param.getPhoneNum());
        if(user != null){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3008, LoginConstant.FAILURE_MSG_3008);
        }
        param.setPassword(password);
        User register = userService.register(param);
        sceneCooperationService.saveByRegister(register,ucenterConfig.getRegisterCooperationMeshNum(),"mesh");
        sceneCooperationService.saveByRegister(register,ucenterConfig.getRegisterCooperationLaserNum(),"laser");
    }

    public JSONObject createLoginQrCode() throws Exception {
        String uuid = NumberUtils.getUUID();
        String filePath = QrCodeFilePath.LOGIN_QR_CODE_PATH + uuid + ".png";
        File file = new File(QrCodeFilePath.LOGO_IMAGE_LOCAL);
        if(!file.exists()){
            fYunFileServiceInterface.downloadFile(QrCodeFilePath.LOGO_IMAGE_OSS,QrCodeFilePath.LOGO_IMAGE_LOCAL);
        }
        MatrixToImageWriterUtil.createQRCode(NacosProperty.getMainUrl() + "app/index.html?m="+uuid, filePath,true,QrCodeFilePath.LOGO_IMAGE_LOCAL);
        JSONObject json = new JSONObject();
        json.put("url", filePath.replace(ConstantFilePath.BASE_PATH, ""));
        json.put("uuid", uuid);
        redisUtil.set(RedisKeyUtil.QRCODE+uuid,uuid,5*60);
        return json;
    }

    public JSONObject sendUserInfo(String uuid) {
        if (StringUtils.isEmpty(uuid)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        //二维码失效，清除本地文件二维码
        if(!redisUtil.hasKey(RedisKeyUtil.QRCODE +uuid)){
            FileUtils.delFile(QrCodeFilePath.LOGIN_QR_CODE_PATH + uuid + ".png");
            throw new BusinessException(LoginConstant.FAILURE_CODE_3035, LoginConstant.FAILURE_MSG_3035);
        }
        if(!redisUtil.hasKey(uuid)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3004, LoginConstant.FAILURE_MSG_3004);
        }
        String childName = redisUtil.get(uuid);
        Camera camera = cameraService.getBySnCode(childName);
        if(camera == null){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3004, LoginConstant.FAILURE_MSG_3004);
        }
        CameraDetail cameraDetail = cameraDetailService.getByCameraId(camera.getId());
        if(cameraDetail == null){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3004, LoginConstant.FAILURE_MSG_3004);
        }
        UserVo userVo = new UserVo();
        userVo.setUserName(childName);
        userVo.setId(cameraDetail.getUserId());
        userVo.setCameraId(camera.getId());
        userVo.setCameraLogin(1);
        String token = this.redisLogin(childName,JSONObject.toJSONString(userVo),"camera");
        JSONObject obj = new JSONObject();
        obj.put("token",token);
        obj.put("childName",childName);
        obj.put("to",1);
        redisUtil.del(uuid);
        FileUtils.deleteFile(QrCodeFilePath.LOGIN_QR_CODE_PATH +uuid +".png");
        return obj;
    }



    public void getEmailAuthCode(String email, String country) throws Exception {
        if(StringUtils.isEmpty(email) || StringUtils.isEmpty(country)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        String code = String.valueOf((int)((Math.random()*9+1)*100000));

        switch (country) {
            case "1":
            case "33":
                mailTemplateService.sendCodeMail(email,code,"en");
                break;
            case "2":
                mailTemplateService.sendCodeMail(email,code,"en");
                break;
            default:
                mailTemplateService.sendCodeMail(email,code,"zh");
                break;
        }

        //删除缓存
        if (redisUtil.hasKey(RedisKeyUtil.PREFIX_MSG_AUTH_CODE + email)){
            redisUtil.del(RedisKeyUtil.PREFIX_MSG_AUTH_CODE + email);
        }
        //短信验证码，5分钟有效
        redisUtil.set(RedisKeyUtil.PREFIX_MSG_AUTH_CODE + email, code, 300);
    }

    public void changePassword(RegisterParam param) {
        if (StringUtils.isEmpty(param.getPassword()) || StringUtils.isEmpty(param.getConfirmPwd()) ||
                StringUtils.isEmpty(param.getMsgAuthCode())
                || StringUtils.isEmpty(param.getPhoneNum())){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3001, LoginConstant.FAILURE_MSG_3001);
        }
        if (!param.getPassword().equals(param.getConfirmPwd())){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3009, LoginConstant.FAILURE_MSG_3009);
        }
        //对前端传的密码解密
        String password;
        if(StringUtils.isNotBlank(param.getClear()) && param.getClear().equals("YES")){
            try {
                String desEncrypt = AesUtil.desEncrypt(param.getPassword());
                password = desEncrypt;
            }catch (Exception e){
                throw new BusinessException(LoginConstant.FAILURE_CODE_3014, LoginConstant.FAILURE_MSG_3014);
            }
        }else {
            password = Base64Converter.decode(Base64Converter.subText(param.getPassword()));
        }
        //正则判断密码是否符合规则（8位以上并且数字英文组合）
        if(!password.matches(ConstantRegex.PASSWORD_REGEX)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3011, LoginConstant.FAILURE_MSG_3011);
        }
        User user = userService.getByUserName(param.getPhoneNum());
        if(user == null){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3015, LoginConstant.FAILURE_MSG_3015);
        }
        if(!param.getMsgAuthCode().equals(registerValidCode)){
            checkSms(param.getMsgAuthCode(),param.getPhoneNum(),true);
        }
        String pwdMd5 = SecurityUtil.MD5(password);
        userService.updatePassword(param.getPhoneNum(), pwdMd5);
    }

    public String redisLogin(String userName,String value,String loginType){
        String token = JwtUtil.createJWT(-1,userName,loginType);
        String redisKey = String.format(RedisKey.TOKEN_V3,token);
        redisUtil.set(redisKey, value,2 * 60 * 60);
        return token;
    }

    public void loginCheck(String token) {
        String redisKey = String.format(RedisKey.TOKEN_V3,token);
        if(!redisUtil.hasKey(redisKey)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3004, LoginConstant.FAILURE_MSG_3004);
        }
    }

    public void checkSms(String msgAuthCode, String userName,boolean del) {
        //验证码校验
        String codeValue = redisUtil.get(RedisKeyUtil.PREFIX_MSG_AUTH_CODE + userName);
        if (StringUtils.isEmpty(codeValue)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3006, LoginConstant.FAILURE_MSG_3006);
        }
        if (!codeValue.equals(msgAuthCode)){
            throw new BusinessException(LoginConstant.FAILURE_CODE_3006, LoginConstant.FAILURE_MSG_3006);
        }
        if(del){
            redisUtil.del(RedisKeyUtil.PREFIX_MSG_AUTH_CODE + userName);
        }
    }

    public LoginVo loginClear(LoginParam param) {
        param.setClear("YES");  //明文登录
        return login(param);
    }

    public static void main(String[] args) throws Exception{
        System.out.println(AesUtil.encrypt("Zkturing@2025!"));
    }
}
