package com.ytpm.lemonios.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ytpm.agent.enums.AdRecordEnum;
import com.ytpm.agent.enums.UserStatusEnum;
import com.ytpm.agent.model.YtDitch;
import com.ytpm.annotation.ApiEncrypt;
import com.ytpm.app.enums.LoginType;
import com.ytpm.app.model.YtAppDefaultConfig;
import com.ytpm.app.model.YtDyzAdRecord;
import com.ytpm.app.model.YtDyzUser;
import com.ytpm.app.param.AppConfigUpdateParam;
import com.ytpm.app.param.DyzAdRecordParam;
import com.ytpm.app.param.IosLoginParam;
import com.ytpm.app.param.WxLoginParam;
import com.ytpm.app.view.IosPowerResView;
import com.ytpm.app.view.IosUserInfo;
import com.ytpm.app.view.WxDefaultConfig;
import com.ytpm.app.view.WxLoginResult;
import com.ytpm.app.view.WxUserInfo;
import com.ytpm.feign.RiskFeign;
import com.ytpm.general.RepMessage;
import com.ytpm.general.Result;
import com.ytpm.general.StatusCode;
import com.ytpm.lemonios.dao.AdRecordMapper;
import com.ytpm.lemonios.dao.AppUserMapper;
import com.ytpm.lemonios.dao.DitchMapper;
import com.ytpm.lemonios.redis.RedisService;
import com.ytpm.lemonios.service.AdService;
import com.ytpm.lemonios.service.AppUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Slf4j
@Api(tags = "微信开放能力模块")
@RestController
@RefreshScope
@RequestMapping("/wx")
public class WxController {

    @Resource
    private AppUserMapper appUserMapper;
    @Resource
    private AdRecordMapper recordMapper;
    @Resource
    private AdService adService;
    @Resource
    private RiskFeign riskFeign;
    @Resource
    private AppUserService appUserService;
    @Resource
    private DitchMapper ditchMapper;
    @Resource
    private RedisService redisService;

    @Value("${yt.ios.appid:}")
    private String appId;

    @Value(" ${risk.config.iplimit.tips:}")
    private String ipLimitTips;

    @Value("${spring.application.name-zh:}")
    private String applicationNameZh;

    private final static String GRANT_TYPE = "authorization_code";


    @Deprecated
    @PostMapping("/login")
    @ApiOperation("微信登录")
    @Transactional
    public Result<YtDyzUser> wxLogin(@RequestBody WxLoginParam param, HttpServletRequest request) {
        //根据应用获取配置调用微信接口登录
        WxDefaultConfig defaultConfig = appUserMapper.getDefaultConfig(param.getAppType());
        if (Objects.isNull(defaultConfig)) {
            return new Result<>(StatusCode.ACCESS_ERR, "微信登录失败，未找到相应配置！");
        }
        param.setAppId(defaultConfig.getPlatformAppId());
        WxLoginResult loginResult = getWechatLoginInfo(param.getWxCode(), param.getAppType(),
                defaultConfig.getAppId(), defaultConfig.getSecret());
        if (Objects.isNull(loginResult) || StrUtil.isBlank(loginResult.getOpenid())) {
            return new Result<>(StatusCode.ACCESS_ERR, "微信登录失败，请刷新授权码！");
        }
        WxUserInfo wxUserInfo = getWechatUserInfo(loginResult.getAccess_token(), loginResult.getOpenid());
        if (Objects.isNull(wxUserInfo)) {
            return new Result<>(StatusCode.ACCESS_ERR, "微信用户登录失败");
        }
        param.setLoginIp(getClientIp(request));
        YtDyzUser old = appUserService.crudForNewTrans(param, wxUserInfo, loginResult);
        //调用风控服务校验默认风控配置
        old.setRiskCode("313");
        Result<?> result = riskFeign.checkRisk(old);
        if (result.getCode() != 200) {
            return new Result<>(StatusCode.ACCESS_ERR, result.getMessage());
        }
        return Result.resultOk(RepMessage.LOGIN_SUCCESS, old);
    }


    /**
     * 获取微信用户信息
     */
    private WxUserInfo getWechatUserInfo(String accessToken, String openid) {
        // 根据token和openid 获取用户信息
        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token={}&openid={}&lang=zh_CN";
        userInfoUrl = StrUtil.format(userInfoUrl, accessToken, openid);
        String curUser = HttpUtil.get(userInfoUrl);
        WxUserInfo wxUserInfo = JSON.parseObject(curUser, WxUserInfo.class);
        log.error("获取的用户信息:{}", wxUserInfo);
        return wxUserInfo;
    }


    /**
     * 微信登录
     */
    private WxLoginResult getWechatLoginInfo(String wxCode, int appType, String appId, String secret) {
        String wxLoginUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={}&secret={}&code={}&grant_type={}";
        wxLoginUrl = StrUtil.format(wxLoginUrl, appId, secret, wxCode, GRANT_TYPE);
        //拿到授权码 请求微信登录返回access_token
        String result = HttpUtil.get(wxLoginUrl);
        WxLoginResult loginResult = JSON.parseObject(result, WxLoginResult.class);
        log.error("授权码获取的登录结果:{}", loginResult);
        return loginResult;
    }


    @ApiOperation("获取IOS登陆幂等Token")
    @GetMapping("/get/requestId")
    public Result<String> getRequestId(@RequestParam("ditchId") String ditchId, @RequestParam("iosId") String iosId) {
        String redisKey = StrUtil.format("visitor:requestId:{}:{}", ditchId, iosId);
        String requestId = "";
        if (redisService.hasKey(redisKey)) {
            requestId = redisService.getStr(redisKey);
        }
        if (StrUtil.isEmpty(requestId)) {
            requestId = IdUtil.fastSimpleUUID();
            boolean setSuccess = redisService.setIfAbsent(redisKey, requestId, 1, TimeUnit.MINUTES);
            if (!setSuccess) {
                requestId = redisService.getStr(redisKey);
                if (StrUtil.isEmpty(requestId)) {
                    requestId = IdUtil.fastSimpleUUID();
                    redisService.setTimeOutMinutesStr(redisKey, requestId, 1);
                } else {
                    redisService.expire(redisKey, 1, TimeUnit.MINUTES);
                }
            }
        }
        return Result.resultObjOk(requestId);
    }

    @Deprecated
    @Transactional
    @ApiOperation("IOS登录校验")
    @PostMapping("/iosLoginCheck")
    public Result<?> iosLoginCheck(@RequestBody IosLoginParam param) {
        YtDyzUser user = appUserMapper.selectByIosId(param.getIosId());
        if (user == null) {
            IosUserInfo userInfo = setIosUserInfo(param);
            user = appUserService.crudForNewTransIos(param, userInfo, LoginType.VISITOR);
        }
        //2.拿3条记录 设置到user
        // TODO 当前仅截取最新三条记录，可能遗漏本次登陆前的风控记录（停落时间过长记录超过三条）
        List<YtDyzAdRecord> adRecordList = recordMapper.getByIosIdBeforeLogin(param.getIosId());
        user.setPreAdRecordList(adRecordList);
        user.setLoginType(LoginType.VISITOR);
        user.setAppId(appId);
        Result<?> result = riskFeign.checkLoginRisk(user);
        if (result.getCode() != 200) {
            String errorMessage = result.getMessage();
            if (user.getLoginType() == LoginType.VISITOR && RepMessage.RISK_VISITOR_LOWER_VALUE.equals(errorMessage)) {
                WxDefaultConfig defaultConfig = appUserMapper.getLastDefaultConfig();
                return Result.resultErr(StrUtil.emptyToDefault(defaultConfig.getLowValueTip(), errorMessage));
            }
            return Result.resultErr(errorMessage);
        }
        YtDyzUser newUser = new YtDyzUser();
        newUser.setUserId(user.getUserId());
        newUser.setUserStatus(UserStatusEnum.NORMAL.getCode());
        appUserMapper.updateUser(newUser);
        return Result.resultOk();
    }

    private IosUserInfo setIosUserInfo(IosLoginParam param) {
        IosUserInfo userInfo = new IosUserInfo();
        userInfo.setOpenid(param.getIosId() == null ? "" : param.getIosId());
        userInfo.setHeadimgurl(param.getIconUrl() == null ? "" : param.getIconUrl());
        if (StrUtil.isEmpty(param.getAlias())) {
            YtDyzUser user;
            if (param.getDitchId() == null) {
                user = appUserMapper.selectByIosId(param.getIosId());
            } else {
                user = appUserMapper.getYtAppUserForIos(param.getIosId(), param.getDitchId());
            }
            if (user == null || StrUtil.isEmpty(user.getNickName())) {
                String nickNamePrefix = "Tourists";
                List<String> list = Arrays.asList("朝暮日记", "班务助手", "成语拼拼乐");
                if (StrUtil.isNotEmpty(applicationNameZh) && list.contains(applicationNameZh)) {
                    nickNamePrefix = applicationNameZh;
                }
                userInfo.setNickname(nickNamePrefix + IdUtil.fastSimpleUUID().substring(0, 8));
            } else {
                userInfo.setNickname(user.getNickName());
            }
        } else {
            userInfo.setNickname(param.getAlias());
        }
        return userInfo;
    }


    @ApiEncrypt(response = true)
    @ApiOperation("IOS登录")
    @PostMapping("/iosLogin")
    @Transactional(rollbackFor = Exception.class)
    public Result<YtDyzUser> iosLogin(@RequestBody IosLoginParam param, HttpServletRequest request) {
        //根据应用ID获取配置调用接口登录
        WxDefaultConfig defaultConfig = appUserMapper.getDefaultConfigByDitchId(param.getDitchId());
        // 当默认配置不存在时，尝试通过渠道信息获取备用配置
        if (Objects.isNull(defaultConfig)) {
            // 1. 检查渠道是否存在（提前拦截无效情况）
            YtDitch ditch = ditchMapper.selectById(param.getDitchId());
            if (ditch != null) {
                // 2. 通过渠道的appId获取备用配置
                defaultConfig = appUserMapper.getByAppId(ditch.getAppId());
            }
        }
        if (Objects.isNull(defaultConfig)) {
            return new Result<>(StatusCode.ACCESS_ERR, "登录失败，未找到相应配置！");
        }
        // 幂等请求校验
        if (StrUtil.isNotEmpty(param.getRequestId())) {
            String redisKey = StrUtil.format("visitor:requestId:{}:{}", param.getDitchId(), param.getIosId());
            if (!redisService.hasKey(redisKey)) {
                return new Result<>(StatusCode.ACCESS_ERR, "登录失败，重复请求！");
            }
            String cacheKey = redisService.getStr(redisKey);
            if (!StrUtil.equals(cacheKey, param.getRequestId())) {
                return new Result<>(StatusCode.ACCESS_ERR, "登录失败，重复请求！");
            }
            redisService.del(redisKey);
        }
        // phoneJson 处理
        if (StrUtil.isNotEmpty(param.getPhoneJson())) {
            JSONObject jsonObject = JSONObject.parseObject(param.getPhoneJson());
            List<String> appList = null;
            if (jsonObject.get("appList") != null) {
                appList = jsonObject.getJSONArray("appList").toJavaList(String.class);
            }
            if (jsonObject.get("app_list") != null) {
                appList = jsonObject.getJSONArray("app_list").toJavaList(String.class);
            }
            if (CollUtil.isNotEmpty(appList)) {
                appList = appList.stream().map(String::toLowerCase).sorted().collect(Collectors.toList());
                jsonObject.put("appList", appList);
                param.setPhoneJson(JSONObject.toJSONString(jsonObject));
            }
        }
        IosUserInfo userInfo = setIosUserInfo(param);
        param.setLoginIp(getClientIp(request));
        // 获取或注册用户
        YtDyzUser dyzUser = appUserService.crudForNewTransIos(param, userInfo, LoginType.IOS);
        // 如果传入游客广告记录，执行游客登陆校验
        if (CollUtil.isNotEmpty(param.getPreAdList())) {
            dyzUser.setLoginType(LoginType.VISITOR);
            List<YtDyzAdRecord> preAdRecordList = saveVisitorAdRecord(dyzUser, param);
            dyzUser.setPreAdRecordList(preAdRecordList);
            Result<?> result = riskFeign.checkLoginRisk(dyzUser);
            if (result.getCode() != 200) {
                String errorMessage = result.getMessage();
                if (RepMessage.RISK_VISITOR_LOWER_VALUE.equals(errorMessage)) {
                    errorMessage = StrUtil.emptyToDefault(defaultConfig.getLowValueTip(), errorMessage);
                }
                return new Result<>(StatusCode.ACCESS_ERR, errorMessage);
            }
        }
        // 状态更新 游客登陆前风控 -> 正常
        YtDyzUser newUser = new YtDyzUser();
        newUser.setUserId(dyzUser.getUserId());
        dyzUser.setUserStatus(UserStatusEnum.NORMAL.getCode());
        newUser.setUserStatus(UserStatusEnum.NORMAL.getCode());
        appUserMapper.updateUser(newUser);
        //调用风控服务校验默认风控配置
        dyzUser.setPhoneJson(param.getPhoneJson());
        dyzUser.setLoginType(LoginType.IOS);
        dyzUser.setRiskCode("313");
        Result<?> result = riskFeign.checkRisk(dyzUser);
        if (result.getCode() != 200) {
            String errorMessage = result.getMessage();
            // 自定义低价值风控提示语
            if (RepMessage.RISK_VISITOR_LOWER_VALUE.equals(errorMessage)) {
                errorMessage = StrUtil.emptyToDefault(defaultConfig.getLowValueTip(), errorMessage);
            }
            // 自定义IP风控提示语
            if (RepMessage.RISK_IP_LIMIT_VALUE.equals(errorMessage) && StrUtil.isNotEmpty(ipLimitTips)) {
                String[] split = ipLimitTips.split(",");
                errorMessage = split[RandomUtil.randomInt(split.length)];
            }
            return new Result<>(StatusCode.ACCESS_ERR, errorMessage);
        }
        if (dyzUser.getLastLoginTime() != null && dyzUser.getRegistryTime() != null) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            dyzUser.setLastLoginTimeStr(sdf.format(dyzUser.getLastLoginTime()));
            dyzUser.setRegistryTimeStr(sdf.format(dyzUser.getRegistryTime()));
        }
        //调用风控服务校验默认风控配置
        return Result.resultOk(RepMessage.LOGIN_SUCCESS, dyzUser);
    }

    private List<YtDyzAdRecord> saveVisitorAdRecord(YtDyzUser ytDyzUser, IosLoginParam visitorLoginParam) {
        List<DyzAdRecordParam> preAdList = visitorLoginParam.getPreAdList();
        // 保存登陆前传递的广告记录
        List<String> adRecordIds = new ArrayList<>();
        if (CollUtil.isNotEmpty(preAdList)) {
            BigDecimal totalRevenue = BigDecimal.ZERO;
            for (DyzAdRecordParam adRecordParam : preAdList) {
                if (adRecordParam == null) {
                    continue;
                }
                adRecordParam.setUserId(ytDyzUser.getUserId());
                adRecordParam.setNickName(ytDyzUser.getNickName());
                adRecordParam.setAppId(ytDyzUser.getAppId());
                adRecordParam.setIosId(ytDyzUser.getIosId());
                adRecordParam.setLoginStatus(AdRecordEnum.LOGIN_BEFORE.getCode());
                String recordId = adService.saveRecordAndChangeUser(adRecordParam, ytDyzUser);
                if (recordId != null) {
                    adRecordIds.add(recordId);
                }
                totalRevenue = adRecordParam.getRevenue() == null ? totalRevenue : totalRevenue.add(adRecordParam.getRevenue());
            }
            log.info(StrUtil.format("[visitor adRecords]userId:{} recordCount:{} revenue:{}",
                    ytDyzUser.getUserId(), adRecordIds.size(), totalRevenue.toPlainString()));
        }
        return CollUtil.isEmpty(adRecordIds) ? new ArrayList<>()
                : recordMapper.selectRecordByIds(AdRecordEnum.LOGIN_BEFORE.getCode(), adRecordIds);
    }

    @ApiEncrypt(response = true)
    @PostMapping("/getByDitchId")
    @ApiOperation("获取默认配置")
    @Transactional
    public Result<WxDefaultConfig> getByDitchId(@RequestBody IosLoginParam param) {
        WxDefaultConfig defaultConfig = appUserMapper.getDefaultConfigByDitchId(param.getDitchId());
        return Result.resultOk(RepMessage.QUERY_SUCCESS, defaultConfig);
    }

    @PostMapping("/getLastOne")
    @ApiOperation("获取最近一条默认配置")
    @Transactional
    public Result<?> getLastOne(@RequestBody YtDitch param) {
        return appUserService.addDefaultConfig(param);
    }

    private String getClientIp(HttpServletRequest request) {
        String xfHeader = request.getHeader("X-Forwarded-For");
        if (xfHeader == null) {
            return request.getRemoteAddr();
        }
        // 可能会有多个IP，这里取第一个逗号前的IP
        return xfHeader.split(",")[0];
    }


    @ApiEncrypt(response = true)
    @Deprecated
    @ApiOperation("获取微信默认配置项")
    @GetMapping("/defaultConfig")
    public Result<WxDefaultConfig> getWxDefaultConfig(int appType) {
        WxDefaultConfig config = appUserMapper.getDefaultConfig(appType);
        if (Objects.isNull(config)) {
            return Result.resultErr("应用类型有误！");
        }
        return Result.resultObjOk(config);
    }

    @ApiOperation("体力增加")
    @GetMapping("/addPower")
    @Transactional(rollbackFor = Exception.class)
    @Deprecated
    public Result<IosPowerResView> addPower(@RequestParam("userId") String userId) {
//        appUserMapper.addOnePower(userId);
//        YtDyzPowerRecord record = new YtDyzPowerRecord();
//        record.setUserId(userId);
//        record.setRecordId(IdUtil.fastSimpleUUID());
//        record.setAddTime(new Date());
//        record.setType(1);
//        record.setRemark("增加体力");
//        appUserMapper.addPowerRecord(record);
        YtDyzUser user = appUserMapper.selectById(userId);
        IosPowerResView view = new IosPowerResView();
        view.setPower(user.getPower());
        return Result.resultOk(RepMessage.ADD_SUCCESS, view);
    }


    @ApiOperation("保存应用默认配置")
    @PostMapping("/saveAppConfig")
    public Result<String> saveAppConfig(@RequestBody YtAppDefaultConfig defaultConfig) {
        appUserMapper.saveAppConfig(defaultConfig);
        return Result.resultOk(RepMessage.SAVE_SUCCESS);
    }


    @ApiOperation("修改应用默认配置")
    @PostMapping("/updateAppConfig")
    public Result<String> updateAppConfig(@RequestBody YtAppDefaultConfig defaultConfig) {
        appUserMapper.updateAppConfig(defaultConfig);
        return Result.resultOk(RepMessage.SAVE_SUCCESS);
    }


    @ApiOperation("修改应用默认配置")
    @PostMapping("/updateAppsConfig")
    public void updateAppsConfig(@RequestBody AppConfigUpdateParam param) {
        if (CollUtil.isNotEmpty(param.getApps()) && param.getDefaultConfig() != null) {
            String appIds = String.join(",", param.getApps());
            List<WxDefaultConfig> configs = appUserMapper.getConfigByIds(appIds);
            YtAppDefaultConfig updateInfo = param.getDefaultConfig();
            for (WxDefaultConfig config : configs) {
                YtAppDefaultConfig appConfig = new YtAppDefaultConfig();
                BeanUtils.copyProperties(config, appConfig);
                if (StrUtil.isNotEmpty(updateInfo.getTakuAppId())) {
                    appConfig.setTakuAppId(updateInfo.getTakuAppId());
                }
                if (StrUtil.isNotEmpty(updateInfo.getTakuKey())) {
                    appConfig.setTakuKey(updateInfo.getTakuKey());
                }
                if (StrUtil.isNotEmpty(updateInfo.getTakuBannerPid())) {
                    appConfig.setTakuBannerPid(updateInfo.getTakuBannerPid());
                }
                if (StrUtil.isNotEmpty(updateInfo.getTakuNativePid())) {
                    appConfig.setTakuNativePid(updateInfo.getTakuNativePid());
                }
                if (StrUtil.isNotEmpty(updateInfo.getTakuRewardPid())) {
                    appConfig.setTakuRewardPid(updateInfo.getTakuRewardPid());
                }
                if (StrUtil.isNotEmpty(updateInfo.getTakuInterstitialPid())) {
                    appConfig.setTakuInterstitialPid(updateInfo.getTakuInterstitialPid());
                }
                appUserMapper.updateAppConfig(appConfig);
            }
        }
    }


    @ApiOperation("根据APP_ID获取配置")
    @GetMapping("/getConfigs")
    public List<WxDefaultConfig> getConfigs(@RequestParam(name = "appIds") String appIds) {
        List<WxDefaultConfig> configs = new ArrayList<>();
        List<WxDefaultConfig> dyzConfigs = appUserMapper.getConfigByIds(appIds);
        if (CollUtil.isNotEmpty(dyzConfigs)) {
            configs.addAll(dyzConfigs);
        }
        return configs;
    }


    @ApiOperation("删除默认配置")
    @GetMapping("/delDefaultConfig")
    public void delDefaultConfig(@RequestParam(name = "appId") String appId) {
        List<WxDefaultConfig> dyzConfig = appUserMapper.getConfigByIds(appId);
        if (CollUtil.isNotEmpty(dyzConfig)) {
            appUserMapper.delByAppId(appId);
            // 同步删除渠道记录
            ditchMapper.deleteByAppId(appId);
        }
    }
}
