package com.ruoyi.framework.web.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ruoyi.basic.service.YjAppUserService;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.AppLoginUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.mall.util.PayConstants;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

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

/**
 * 登录校验方法
 *
 * @author ruoyi
 */
@Component
public class AppLoginService
{
    @Autowired
    private TokenService tokenService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private YjAppUserService appUserService;

    @Autowired
    private ISysConfigService configService;
    @Autowired
    @Qualifier("AppUseAuthenticationManager")
    private AuthenticationManager  appUserAuthenticationManager;

    /**
     * 登录验证
     *
     * @param phoneNumber 手机号
     * @param password 密码
     * @param code 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public String login(String phoneNumber, String password, String code, String uuid,String registerId,String miniAppCode)
    {
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        // 验证码开关
        if (captchaEnabled)
        {
            validateCaptcha(code, uuid);
        }
        // 用户验证
        Authentication authentication = null;

        //UsernamePasswordAuthenticationToken是Authenticatiion的实现类
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(phoneNumber, password);

        //这里设置成上下文的意图是在身份验证过程中，
        //其他组件或方法可以获取到该对象，以便进行相关的操作，
        //比如记录登录日志、获取用户信息等。
        AuthenticationContextHolder.setContext(authenticationToken);

        // 该方法会去调用AppUserDetailsServiceImpl.loadUserByUsername
        authentication = appUserAuthenticationManager.authenticate(authenticationToken);

//        AuthenticationContextHolder.clearContext();
        AppLoginUser loginUser = (AppLoginUser) authentication.getPrincipal();

        boolean update=false;
        UpdateWrapper wrapper=new UpdateWrapper<AppUser>().eq("app_user_id",loginUser.getAppUserId());

        //设备id
        if (StrUtil.isNotEmpty(loginUser.getAppUser().getRegisterId())&&!loginUser.getAppUser().getRegisterId().equals(registerId)){
            wrapper.set("register_id",registerId);
            update=true;
        }
        //小程序登录
        if (StrUtil.isNotEmpty(miniAppCode) && StrUtil.isEmpty(loginUser.getAppUser().getOpenid())){

            HashMap<String, Object> map=getOpenId(miniAppCode);
            wrapper.set(ObjectUtil.isNotEmpty(map.get("openId")),"openid",map.get("openId").toString());
            wrapper.set(ObjectUtil.isNotEmpty(map.get("unionId")),"unionid",map.get("unionId").toString());
            update=true;
        }
        if (update){
            appUserService.update(wrapper);
        }

        //将登录信息存入到数据库
        wrapper.set("login_ip",IpUtils.getIpAddr(ServletUtils.getRequest()));
        wrapper.set("login_date",DateUtils.getNowDate());
        appUserService.update(wrapper);

        // 生成token
        return tokenService.createAppToken(loginUser);
    }

    /**
     * 校验验证码
     *
     * @param code 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public void validateCaptcha(String code, String uuid)
    {
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null)
        {
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha))
        {
            throw new CaptchaException();
        }
    }




    //获取openid
    public HashMap<String, Object> getOpenId(String code) {
        //appid secret 配置到application里
        String url="https://api.weixin.qq.com/sns/jscode2session?appid="+ PayConstants.MINI_APP_ID +"&secret="+PayConstants.MINI_APP_SECRET+"&js_code="+code+"&grant_type=authorization_code";
        OkHttpClient client=new OkHttpClient();
        Request request=new Request.Builder().url(url).build();
        Response response= null;
        HashMap<String, Object> userInfoMap = new HashMap<>();

        try {
            response = client.newCall(request).execute();

            if(response.isSuccessful()){//请求成功
                String body=response.body().string();
                Map mapTypes = JSON.parseObject(body);
//                String session_key = mapTypes.get("session_key").toString();
                String openId=mapTypes.get("openid").toString();
//                userInfoMap.put("session_key",session_key);
                userInfoMap.put("openId",openId);
                if(ObjectUtil.isNotEmpty(mapTypes.get("unionid"))){
                    String unionId=mapTypes.get("unionid").toString();
                    userInfoMap.put("unionId",unionId);
                }
                return userInfoMap;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
}
