package com.zanxiang.game.module.manage.service.impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
import com.zanxiang.advertising.tencent.base.pojo.dto.CreateUserActionSetRpcDTO;
import com.zanxiang.advertising.tencent.base.rpc.IUserActionSetRpc;
import com.zanxiang.game.module.base.pojo.enums.DeleteEnum;
import com.zanxiang.game.module.base.pojo.enums.GameCategoryEnum;
import com.zanxiang.game.module.base.pojo.enums.StatusEnum;
import com.zanxiang.game.module.manage.pojo.dto.GameAppletConfigDTO;
import com.zanxiang.game.module.manage.pojo.dto.GameAppletDTO;
import com.zanxiang.game.module.manage.pojo.dto.GameDTO;
import com.zanxiang.game.module.manage.service.IGameAppletService;
import com.zanxiang.game.module.manage.service.IGameService;
import com.zanxiang.game.module.mybatis.entity.Game;
import com.zanxiang.game.module.mybatis.entity.GameApplet;
import com.zanxiang.game.module.mybatis.mapper.GameAppletMapper;
import com.zanxiang.module.oss.service.IOssService;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.URIUtil;
import com.zanxiang.module.util.bean.BeanUtil;
import com.zanxiang.module.util.exception.BaseException;
import com.zanxiang.module.util.pojo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedInputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author : lingfeng
 * @time : 2022-07-08
 * @description : 微信小游戏(小程序)
 */
@Slf4j
@Service
public class GameAppletServiceImpl extends ServiceImpl<GameAppletMapper, GameApplet> implements IGameAppletService {

    @DubboReference(providedBy = AdvertisingTencentServer.SERVER_DUBBO_NAME)
    private IUserActionSetRpc userActionSetRpc;

    @Autowired
    private IOssService ossService;

    @Autowired
    private IGameService gameService;

    @Override
    public boolean addOrUpdate(Game game, GameAppletConfigDTO gameAppletConfigDTO) {
        GameApplet gameApplet = super.getOne(new LambdaQueryWrapper<GameApplet>()
                .eq(GameApplet::getAppId, gameAppletConfigDTO.getAppId())
                .eq(GameApplet::getGameId, game.getId())
        );
        if (gameApplet == null) {
            gameApplet = GameApplet.builder()
                    .gameId(game.getId())
                    .appId(gameAppletConfigDTO.getAppId())
                    .ghId(gameAppletConfigDTO.getGhId())
                    .appName(gameAppletConfigDTO.getAppName())
                    .appSecret(gameAppletConfigDTO.getAppSecret())
                    .type(gameAppletConfigDTO.getType())
                    .shareTitle(gameAppletConfigDTO.getShareTitle())
                    .sharePath(gameAppletConfigDTO.getSharePath())
                    .shareImg(gameAppletConfigDTO.getShareImg())
                    .company(gameAppletConfigDTO.getCompany())
                    .account(gameAppletConfigDTO.getAccount())
                    .manager(gameAppletConfigDTO.getManager())
                    .isDelete(DeleteEnum.NO.getCode())
                    .status(StatusEnum.YES.getCode())
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .build();
        } else {
            gameApplet.setAppId(gameAppletConfigDTO.getAppId());
            gameApplet.setGhId(gameAppletConfigDTO.getGhId());
            gameApplet.setAppName(gameAppletConfigDTO.getAppName());
            gameApplet.setAppSecret(gameAppletConfigDTO.getAppSecret());
            gameApplet.setType(gameAppletConfigDTO.getType());
            gameApplet.setShareTitle(gameAppletConfigDTO.getShareTitle());
            gameApplet.setSharePath(gameAppletConfigDTO.getSharePath());
            gameApplet.setShareImg(gameAppletConfigDTO.getShareImg());
            gameApplet.setCompany(gameAppletConfigDTO.getCompany());
            gameApplet.setAccount(gameAppletConfigDTO.getAccount());
            gameApplet.setManager(gameAppletConfigDTO.getManager());
            gameApplet.setUpdateTime(LocalDateTime.now());
        }
        this.createActionSet(game.getCategory(), game.getIsPut(), gameAppletConfigDTO.getAppId(), game.getName());
        return super.saveOrUpdate(gameApplet);
    }

    @Override
    public Boolean createActionSet(Long gameId) {
        GameDTO gameDTO = gameService.getById(gameId);
        GameAppletDTO gameAppletDTO = this.getByGameId(gameId);
        if (gameDTO == null || gameAppletDTO == null) {
            log.error("创建数据源失败, 游戏信息数据不全 gameDTO : {}, gameAppletDTO : {}",
                    JsonUtil.toString(gameDTO), JsonUtil.toString(gameAppletDTO));
            return Boolean.FALSE;
        }
        return this.createActionSet(gameDTO.getCategory(), gameDTO.getIsPut(), gameAppletDTO.getAppId(), gameDTO.getName());
    }

    private Boolean createActionSet(Long gameCategory, Boolean isPut, String appId, String gameName) {
        CreateUserActionSetRpcDTO actionSetRpcDTO = CreateUserActionSetRpcDTO.builder()
                .appId(appId).type("WEB").name(gameName + "Web数据源").unique(Boolean.TRUE).build();
        //小游戏和H5的类型才需要创建数据源
        List<Long> categoryList = Arrays.asList(GameCategoryEnum.CATEGORY_WX_APPLET.getId(), GameCategoryEnum.CATEGORY_H5.getId());
        //投放的游戏才需要设置数据源
        if (!categoryList.contains(gameCategory) || !Objects.equals(isPut, Boolean.TRUE)) {
            return Boolean.FALSE;
        }
        //调用回传服务创建数据源
        ResultVO<Boolean> booleanResultVO = null;
        try {
            log.error("数据源创建提交参数, actionSetRpcDTO : {}", JsonUtil.toString(actionSetRpcDTO));
            booleanResultVO = userActionSetRpc.create(actionSetRpcDTO);
        } catch (Exception e) {
            log.error("调用回传服务创建数据源异常, gameCategory : {}, appId : {}, actionSetRpcDTO : {}, e : {}",
                    gameCategory, appId, JsonUtil.toString(actionSetRpcDTO), e.getMessage());
        }
        log.error("创建数据源结果 actionSetRpcDTO : {}, booleanResultVO : {}",
                JsonUtil.toString(actionSetRpcDTO), JsonUtil.toString(booleanResultVO));
        return booleanResultVO == null ? Boolean.FALSE : booleanResultVO.getData();
    }

    @Override
    public GameAppletDTO getByGameId(Long gameId) {
        GameApplet gameApplet = super.getOne(new LambdaQueryWrapper<GameApplet>()
                .eq(GameApplet::getGameId, gameId));
        if (gameApplet == null) {
            return null;
        }
        return BeanUtil.copy(gameApplet, GameAppletDTO.class);
    }

    /**
     * 获取游戏小程序二维码
     *
     * @param appId       : 小程序appId
     * @param appSecret   : 小程序密钥
     * @param ossFileName : oss文件名
     * @return : 返回oss二维码图片地址
     */
    @Override
    public String getQrCode(String appId, String appSecret, String ossFileName) {
        if (Strings.isBlank(appId) || Strings.isBlank(appSecret)) {
            throw new BaseException("参数错误, 缺少小程序信息");
        }
        //oss文件名
        ossFileName = Strings.isBlank(ossFileName) ? UUID.randomUUID().toString() + ".jpg" : ossFileName + ".jpg";
        //获取小程序token
        String token = this.getAppletTokenApi(appId, appSecret);
        //获取小程序二维码
        BufferedInputStream inputStream = this.getQrCodeApi(null, token);
        //二维码上传到oss, 返回网络地址
        return ossService.upload(ossFileName, inputStream);
    }

    /**
     * 获取小程序token
     *
     * @param appId  : 小程序appId
     * @param secret : 小程序密钥
     * @return : 返回小程token
     */
    private String getAppletTokenApi(String appId, String secret) {
        Map<String, String> paramMap = new HashMap<>(3);
        paramMap.put("grant_type", "client_credential");
        paramMap.put("appid", appId);
        paramMap.put("secret", secret);
        String url = "https://api.weixin.qq.com/cgi-bin/token";
        //拼接url请求参数
        String uri = URIUtil.fillUrlParams(url, paramMap, Boolean.TRUE);
        // 带参GET请求
        Map<String, String> resultMap = new HashMap<>(4);
        try {
            String result = HttpUtil.get(uri);
            if (Strings.isNotBlank(result)) {
                resultMap = JsonUtil.toMap(result, Map.class, String.class, String.class);
            }
        } catch (Exception e) {
            log.error("获取小程序token出现异常, appId : {},secret: {} e : {}", appId, secret, e.getMessage());
            throw new BaseException("获取小程序token出现异常");
        }
        //返回token
        if (resultMap.containsKey("access_token")) {
            return resultMap.get("access_token");
        }
        //没有拿到token
        log.error("获取token发生错误, appId : {}, secret: {}, errcode : {}, errmsg : {}", appId, secret,
                resultMap.get("errcode"), resultMap.get("errmsg"));
        throw new BaseException("http状态正确, 获取token发生错误");
    }

    /**
     * 生成微信小程序二维码
     *
     * @param scene       : 二维码携带的参数
     * @param accessToken : 小程序密钥
     * @return : 返回二维码文件流
     */
    private BufferedInputStream getQrCodeApi(String scene, String accessToken) {
        try {
            //调用微信接口生成二维码
            URL url = new URL("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            //连接超时 单位毫秒
            connection.setConnectTimeout(10000);
            //读取超时 单位毫秒
            connection.setReadTimeout(2000);
            // 发送POST请求必须设置如下两行
            connection.setDoOutput(true);
            connection.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            PrintWriter printWriter = new PrintWriter(connection.getOutputStream());
            // 发送请求参数
            JSONObject paramJson = new JSONObject();
            //这就是你二维码里携带的参数 String型  名称不可变
            paramJson.set("scene", Strings.isBlank(scene) ? "a=1" : scene);
            printWriter.write(paramJson.toString());
            // flush输出流的缓冲
            printWriter.flush();
            //返回数据流
            return new BufferedInputStream(connection.getInputStream());
        } catch (Exception e) {
            throw new BaseException("获取小程序二维码异常");
        }
    }
}
