package com.bonus.auth.service;

import com.alibaba.fastjson.JSONObject;
import com.bonus.auth.config.VerificationCodeType;
import com.bonus.auth.factory.VerificationCodeStrategyFactory;
import com.bonus.auth.form.RegisterBody;
import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.constant.UserConstants;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.encryption.Sm4Utils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.config.SystemConfig;
import com.bonus.system.api.RemoteConfigService;
import com.bonus.system.api.RemoteUserService;
import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.model.LoginUser;
import com.hankcs.hanlp.HanLP;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录校验方法
 * 提供登录、注册、验证码获取等服务
 */
@Component
@Slf4j
public class SysLoginService {
    @Resource
    private RemoteUserService remoteUserService;


    @Autowired
    private SysRecordLogService recordLogService;


    @Resource
    private PasswordValidatorService passwordValidatorService;

    @Resource
    private VerificationCodeStrategyFactory verificationCodeStrategyFactory;
    @Autowired
    private SystemConfig systemConfig;

    @Resource
    private RemoteConfigService configService;

    /**
     * 获取验证码
     *
     * @param username             用户名或手机号
     * @param verificationCodeType 获取验证码类型（register：注册，其他：登录）
     * @return 响应结果
     */
    public R<?> getPhoneCode(String username, VerificationCodeType verificationCodeType) {
        // 获取相应的登录策略
        VerificationCodeStrategy strategyFactory = verificationCodeStrategyFactory.getStrategy(verificationCodeType);
        if (strategyFactory == null) {
            return R.fail("不支持的方式");
        }
        strategyFactory.sendVerificationCode(username);
        return R.ok();
    }

    /**
     * 用户登出
     *
     * @param loginName 登录名
     * @param userId    用户ID
     */
    public void logout(String loginName, String userId) {
        try {
            recordLogService.saveLogout(loginName, "成功", "成功", userId, "成功");
        } catch (Exception e) {
            recordLogService.saveLogs(loginName, System.currentTimeMillis(), "登出异常", e.getMessage(), null, "失败");
            throw new ServiceException("退出失败，请稍后重试");
        }
    }

    /**
     * 用户注册
     *
     * @param registerBody 注册信息
     */
    public void register(RegisterBody registerBody) {
        log.info("开始进行注册===============");
        long startTime = System.currentTimeMillis(); // 记录开始时间
        String result = convertAndAppend(registerBody.getNickName(), registerBody.getMobile());
        int contactType = getContactType(registerBody.getMobile());

        if (contactType == 0) {
            R<LoginUser> userResult = remoteUserService.getUserInfoByEmail(registerBody.getMobile() , SecurityConstants.INNER);
            if (userResult.getData() != null) {
                throw new ServiceException("联系方式已经注册账号");
            }
        } else if (contactType == 1) {
            R<LoginUser> userResult = remoteUserService.getUserInfoByPhone(registerBody.getMobile() , SecurityConstants.INNER);
            if (userResult.getData() != null) {
                throw new ServiceException("联系方式已经注册账号");
            }
        }else {
            throw new ServiceException("请输入正确的联系方式");
        }
        registerBody.setUsername(result);
        if (StringUtils.isAnyBlank(registerBody.getUsername(), registerBody.getPassword()) ||
                registerBody.getUsername().length() < UserConstants.USERNAME_MIN_LENGTH ||
                registerBody.getUsername().length() > UserConstants.USERNAME_MAX_LENGTH) {
            recordLogService.saveLogs(registerBody.getUsername(), startTime, "注册参数无效", "账户或密码长度不符合要求", null, "失败");
            throw new ServiceException("账户或密码长度不符合要求");
        }
        if (systemConfig.getRegistersConfig().isVerificationCode()){
            passwordValidatorService.checkPhoneCaptcha(registerBody.getMobile(),registerBody.getVerificationCode());
        }
        AjaxResult ajaxResult = passwordValidatorService.validatePassword(registerBody.getUsername(), registerBody.getPassword());

        if (ajaxResult.isError()) {
            throw new ServiceException((String) ajaxResult.get("msg"));
        }
        SysUser sysUser = new SysUser();
        sysUser.setUserName(registerBody.getUsername());
        sysUser.setNickName(registerBody.getNickName());
        sysUser.setDeptId(registerBody.getDeptId());
        if (systemConfig.getRegistersConfig().isApprovalStatus()){
            sysUser.setApprovalStatus("0");
            sysUser.setStatus("1");
        }else {
            sysUser.setApprovalStatus("1");
            sysUser.setStatus("0");
        }
        //有要求另加
        sysUser.setPassword(SecurityUtils.encryptPassword(registerBody.getPassword()));
        if (getContactType(registerBody.getMobile()) == 1) {
            sysUser.setPhonenumber(registerBody.getMobile());
        } else {
            sysUser.setEmail(registerBody.getMobile());
        }

        try {
            R<?> registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER);
            if (R.FAIL == registerResult.getCode()) {
                recordLogService.saveLogs(registerBody.getUsername(), startTime, "注册失败", registerResult.getMsg(), null, "失败");
                throw new ServiceException(registerResult.getMsg());
            }

            recordLogService.recordLogininfor(registerBody.getUsername(), Constants.REGISTER, "注册成功");
        } catch (Exception e) {
            recordLogService.saveLogs(registerBody.getUsername(), startTime, "注册异常", e.getMessage(), null, "失败");
            throw new ServiceException("注册失败，请稍后重试");
        }
        log.info("结束进行注册===============");
    }

    /**
     * 获取联系方式类型
     *
     * @param contactInfo 联系方式
     * @return 联系方式类型（0：邮箱，1：手机号，2：无效）
     */
    public static int getContactType(String contactInfo) {
        String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
        String phoneRegex = "^1[3-9]\\d{9}$";
        if (contactInfo.matches(emailRegex)) {
            return 0;
        } else if (contactInfo.matches(phoneRegex)) {
            return 1;
        } else {
            return 2;
        }
    }

    /**
     * 将中文转换为拼音并拼接联系方式
     *
     * @param chineseText 中文文本
     * @param contactInfo 联系方式
     * @return 拼接后的字符串
     */
    public static String convertAndAppend(String chineseText, String contactInfo) {
        String pinyin = HanLP.convertToPinyinString(chineseText, "", true);
        int contactType = getContactType(contactInfo);

        if (contactType == 0) {
            return pinyin + "_" + contactInfo.substring(0, 4);
        } else if (contactType == 1) {
            return pinyin + "_" + contactInfo.substring(contactInfo.length() - 4);
        } else {
            return pinyin;
        }
    }

    /**
     * i皖送Web端登录
     * @param ticket
     * @param iwsWebAppId
     * @param iwsWebUrl
     * @return
     */
    public LoginUser iwsWebLogin(String ticket, String iwsWebAppId, String iwsWebUrl) {
        Map<String, Object> paramMap = new HashMap<>();
        LoginUser loginUser = new LoginUser();
        SysUser sysUser = new SysUser();
        paramMap.put("ticket", ticket);
        paramMap.put("appId", iwsWebAppId);
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> authResponse = restTemplate.getForEntity(iwsWebUrl, String.class, paramMap);
        log.info("authResponse:" + authResponse.toString());
        // 根据ResponseEntity<String> responseEntity对象，获取body部分，body为json格式字符串
        String content = authResponse.getBody();
        // 将json字符串转化为json对象
        JSONObject json = JSONObject.parseObject(content);
        // 取出data部分对象
        JSONObject data = json.getJSONObject("data");

        if ("200".equals(json.getInteger("code").toString())){
            sysUser.setUserName(data.get("userName").toString());
            sysUser.setNickName(data.get("name").toString());
            sysUser.setPhonenumber(data.get("mobile").toString());
            loginUser.setSysUser(sysUser);
            loginUser = createUser(sysUser,loginUser);
        }
        return loginUser;
    }

    /**
     * 先查，如果没有进行创建
     * @param sysUser
     * @param loginUser
     */
    private LoginUser createUser(SysUser sysUser, LoginUser loginUser) {
        //通过用户名获取人员信息
        LoginUser loginUserNew = new LoginUser();
        SysUser sysUserNew = new SysUser();
        String resultName = convertAndAppend(sysUser.getNickName(), sysUser.getPhonenumber());
        R<LoginUser> userResult = remoteUserService.getUserInfo(resultName, SecurityConstants.INNER);

        if (userResult.getData() == null || R.FAIL == userResult.getCode()) {
            log.info("登录用户不存在,进行创建----");
            RegisterBody registerBody = new RegisterBody();
            registerBody.setUsername(sysUser.getUserName());
            registerBody.setNickName(sysUser.getNickName());
            registerBody.setMobile(sysUser.getPhonenumber());
            registerBody.setDeptId(1L);
            registerBody.setPassword("Bonus@Max2024");
            //获取配置中的初始密码
            AjaxResult result = configService.getConfigKey("sys.user.initPassword");
            if ("200".equals(result.get("code").toString()))
            {
                registerBody.setPassword(result.get("msg").toString());
            }
            log.info("开始进行注册{}",registerBody);
            //新用户注册
            try {
                register(registerBody);
                log.info("注册成功！");
                //查询用户信息
                userResult = remoteUserService.getUserInfo(resultName, SecurityConstants.INNER);
                loginUserNew = userResult.getData();
                sysUserNew = loginUserNew.getSysUser();
                log.info("获取用户信息成功！{}",loginUserNew.getSysUser());
                //初始化一个角色
                Long[] roleIds = new Long[5];
                // 将数组的第一个元素赋值为 2
                roleIds[0] = 2L;
                log.info("开始绑定角色信息{}",roleIds);
                remoteUserService.insertAuthRole(sysUserNew.getUserId(),roleIds,SecurityConstants.INNER);
                log.info("角色信息绑定成功！");
            }catch (Exception e){
                throw new ServiceException("登录失败，请稍后重试");
            }
        }else {
            loginUserNew = userResult.getData();
        }
        return  loginUserNew;
    }

    /**
     * i皖送H5端登录
     * @param ticket
     * @param iwsH5AppId
     * @param iwsH5Url
     * @return
     */
    public LoginUser iwsH5Login(String ticket, String iwsH5AppId, String iwsH5Url) {
        Map<String, Object> paramMap = new HashMap<>();
        LoginUser loginUser = new LoginUser();
        SysUser sysUser = new SysUser();
        paramMap.put("ticket", ticket);
        paramMap.put("appId", iwsH5AppId);
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> authResponse = restTemplate.getForEntity(iwsH5Url, String.class, paramMap);
        log.info("authResponse:" + authResponse.toString());
        // 根据ResponseEntity<String> responseEntity对象，获取body部分，body为json格式字符串
        String content = authResponse.getBody();
        // 将json字符串转化为json对象
        JSONObject json = JSONObject.parseObject(content);
        // 取出data部分对象
        JSONObject data = json.getJSONObject("data");
        log.info("返回的数据:" + data);
        if ("200".equals(json.getInteger("code").toString())){

            JSONObject userInfo = data.getJSONObject("userInfo");
            sysUser.setUserName(userInfo.get("userName").toString());
            sysUser.setNickName(userInfo.get("name").toString());
            sysUser.setPhonenumber(userInfo.get("mobile").toString());
            loginUser.setSysUser(sysUser);
            loginUser = createUser(sysUser,loginUser);
        }
         return loginUser;
    }
}
