package com.td.boss.game.comusers.controller;

import com.alibaba.fastjson.JSON;
import com.td.boss.common.controller.*;
import com.td.boss.common.pojo.Result;
import com.td.boss.game.complayersattri.pojo.ComPlayersAttri;
import com.td.boss.game.complayersattri.service.ComPlayersAttriService;
import com.td.boss.game.complayersattri.vo.ComPlayersAttriSimpleVo;
import com.td.boss.game.complayersattri.vo.ComPlayersAttriVo;
import com.td.boss.game.comsetting.service.ComSettingService;
import com.td.boss.game.comsetting.vo.ComSettingSimpleVo;
import com.td.boss.game.comsetting.vo.ComSettingVo;
import com.td.boss.game.comusers.vo.ComUsersSimpleVo;
import com.td.boss.game.dappWs.DappWSServer;
import com.td.boss.config.enums.ResultEnum;
import com.td.boss.game.comusers.pojo.ComUsers;
import com.td.boss.game.comusers.vo.ComUsersVo;
import com.td.boss.game.comusers.service.ComUsersService;
import com.td.boss.sys.syssetting.vo.SysSettingVo;
import com.td.boss.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import javax.script.ScriptException;
import java.io.IOException;
import java.util.*;

import static com.td.boss.util.MD5Util.createSign;

@Slf4j
@RestController
@RequestMapping("/game/comUsers/")
public class ComUsersController extends CommonController<ComUsersVo, ComUsers, String> {
    @Autowired
    private ComUsersService comUsersService;

    @Autowired
    private ComPlayersAttriService comPlayersAttriService;

    @Autowired
    private ComSettingService comSettingService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;


    @Value("${spring.profiles.active}")
    private String active;

    @Value(value = "classpath:static/dapp/dapp-plugin.min.js")
    private Resource dappPluginFile;
    @Value(value = "classpath:static/dapp/dapp.js")
    private Resource dappFile;

    @Autowired
    private RedisLock redisLock;

    /**
     * 接口需要token放行
     *
     * @return
     */
    @GetMapping("publicKeyAndSys")
    public Result<Map> publicKeyAndSys() throws ScriptException, IOException, NoSuchMethodException {
        //ScriptEngineManager factory = new ScriptEngineManager();
        //ScriptEngine engine = factory.getEngineByName ("JavaScript");
        ////engine.eval("load('"+dappPluginFile.getURL()+"')");
        //engine.eval("load('"+dappFile.getURL()+"')");
        //Invocable inv = (Invocable) engine;
        //inv.invokeFunction("dappInit", "hello");
        //RunScript rs = new RunScript("D:\\CocosProject\\2.1.4\\FragrantTown_Server\\src\\main\\resources\\static\\dapp\\dapp.js");
        //rs.start();

        log.info("login active:" + active);
        //todo 正常流程下，需要获取验证登录过的信息来处理token，这里暂时走测试信息流程
        String userId;
        //系统信息
        SysSettingVo sys = SysSettingUtil.getSysSetting();
        //后端公钥
        String publicKey = RsaUtil.getPublicKey();
        //final String token = jwtTokenUtil.generateToken(userId);
        Map map = new HashMap();
        map.put("publicKey", publicKey);
        map.put("sysApiEncrypt", sys.getSysApiEncrypt());
        return Result.of(map);
    }

    /**
     * 该方法已废弃，后续使用 loginTokenAndVerification 来代替
     *
     * @param loginId
     * @return
     */
    @Deprecated
    @GetMapping("loginToken")
    public Result<Map> userLogin(@RequestParam(value = "loginId", required = false) String loginId) {
        log.info("login active:" + active);
        String userId;
        if (active.equals("dev")) {
            //if(loginId == null || !loginId.equals("1")){
            //    return Result.of(null,false,"请输入参数 loginId = '1' ",ResultEnum.NO_PARAMETERS_CARRIED.getCode());
            //}
            //如果测试环境中，提供测试账号
            userId = loginId;
        } else {
            // 正式环境
            userId = loginId;
        }

        ComUsersVo comUsersVo = comUsersService.findByUserId(userId);

        if (comUsersVo == null) {
            //如果没有用户信息
            comUsersVo = new ComUsersVo();
            comUsersVo.setUserId(userId);
            comUsersVo.setGold(0);
            comUsersVo.setDiamond(0);
            comUsersVo.setCnt(0);
            comUsersVo.setSnb(0);
            comUsersService.save(comUsersVo);
        }

        //生成token
        final String token = jwtTokenUtil.generateToken(comUsersVo.getUserId());
        Map map = new HashMap();
        map.put("active", active);
        map.put("token", token);
        return Result.of(map);
    }


    /**
     * {
     * "address": "TDw6xsVnDJWsdRBLkWAwXbv4hE2X2JQs5z", // 签名地址
     * "id": 1, // 所属账户ID
     * "signature": "0x09fda37fcad4a9bb7b72f652323881a33847be3a44e4403c7a576b3383df30ec6e5e256f28fbdbac5eb0642f304f331783f36d70b5e6fd576818bc42e14624191c", // 用户私钥签名文本
     * "timestamp": 1641279989, // 签名时间戳，需要在1分钟内完成验签，否则本次签名失效
     * "sign": "794DA326066EAAC0F9E0D3E94E306B38" // 微信参数签名
     * }
     * {
     * "address": "TDw6xsVnDJWsdRBLkWAwXbv4hE2X2JQs5z", // 签名地址
     * "id": 1, // 所属账户ID
     * "signature": "0x09fda37fcad4a9bb7b72f652323881a33847be3a44e4403c7a576b3383df30ec6e5e256f28fbdbac5eb0642f304f331783f36d70b5e6fd576818bc42e14624191c", // 签名文本
     * "timestamp": 1641279989 // 签名时间戳，需要在1分钟内完成验签，否则本次签名失效
     * }
     *
     * @param address   签名地址
     * @param id        所属账户ID
     * @param signature 签名文本
     * @param timestamp 签名时间戳，需要在1分钟内完成验签，否则本次签名失效
     * @return
     */
    @PostMapping("loginTokenAndVerification")
    public Result<Map> loginTokenAndVerification(
            @RequestParam(value = "address") String address,
            @RequestParam(value = "id") String id,
            @RequestParam(value = "signature") String signature,
            @RequestParam(value = "timestamp") Integer timestamp) {

        log.info("loginTokenAndVerification active:" + active);
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        parameters.put("address", address);
        parameters.put("id", id);
        parameters.put("signature", signature);
        parameters.put("timestamp", timestamp);


        String sign = createSign(parameters);
        //log.info("sign:" + sign);
        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
        form.add("address", address);
        form.add("id", id);
        form.add("signature", signature);
        form.add("timestamp", timestamp);
        form.add("sign", sign);
        //验证地址
        String DAppOnlineUrl = "https://yt.landownership.live/api/account/loginValidate";
        String DAppTestUrl = "https://wp.landownership.live/api/account/loginValidate";

        String DAppUrl = active.equals("prod") ? DAppOnlineUrl : DAppTestUrl;
        log.info("DApp登录地址：" + DAppUrl);
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        //设置content-type
        MediaType type = MediaType.parseMediaType("multipart/form-data");
        headers.setContentType(type);
        // 以表单的方式提交
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //用HttpEntity封装整个请求报文
        HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<>(form, headers);
        String response = "";
        Map map = new HashMap();

        String _redisKey = "SNB_SAVE_" + id;
        //todo snb冻结加锁
        long time = System.currentTimeMillis() + RedisData.getSnbTimeout();
        try {
            response = restTemplate.postForObject(DAppUrl, files, String.class);
            log.info("response={}", response);
            //如果校验通过，生成用户数据，生成token
            ComUsersVo comUsersVo = comUsersService.findByUserId(id);
            if (comUsersVo == null) {
                //如果没有用户信息
                comUsersVo = new ComUsersVo();
                comUsersVo.setUserId(id);
                comUsersVo.setGold(0);
                comUsersVo.setDiamond(0);
                comUsersVo.setCnt(0);
                comUsersVo.setSnb(0);
                comUsersVo.setSnbPart(0d);
                comUsersVo.setLimitTran(0);
                comUsersVo.setLimitLogin(0);
                comUsersVo.setAddress(address);
                comUsersVo.setLastLogin(new Date());
                comUsersVo.setCreateTime(new Date());
                comUsersService.save(comUsersVo);
            } else {
                //如果是黑名单限制登录的用户，限制登录
                if (comUsersVo.getLimitLogin().equals(1)) {
                    map.put("msg", "当前用户限制登录，请联系游戏管理人员！");
                    return Result.of(map, false, ResultEnum.USER_LIMIT_LOGIN.getMessage(), ResultEnum.USER_LIMIT_LOGIN.getCode());
                }
                //记录一下用户的Address
                if (comUsersVo.getAddress() == null) {
                    comUsersVo.setAddress(address);
                }
                //维护一个最后登录时间
                comUsersVo.setLastLogin(new Date());

                // 防止重复操作
                if (!redisLock.lock(_redisKey, String.valueOf(time))) {
                    return Result.of(map, false, ResultEnum.USER_LOGIN_LOCK.getMessage(), ResultEnum.USER_LOGIN_LOCK.getCode());
                }
                comUsersService.save(comUsersVo);
                redisLock.unlock(_redisKey, String.valueOf(time));

            }
            //生成token
            final String token = jwtTokenUtil.generateToken(comUsersVo.getUserId());
            map.put("token", token);
            map.put("active", active);
            map.put("userInfo", CopyUtil.copy(comUsersVo, ComUsersSimpleVo.class));

            //获取一下用户属性，新增表
            ComPlayersAttriVo playersAttribute = comPlayersAttriService.findByUserId(comUsersVo.getUserId());
            if (playersAttribute == null) {
                // todo player 如果角色不存在的话，直接创建一个。
                playersAttribute = new ComPlayersAttriVo();
                playersAttribute.setUserId(comUsersVo.getUserId());
                playersAttribute.setStrength(0);
                playersAttribute.setLucky(0);
                playersAttribute.setResetStrength(DateUtil.getNowDate());
                playersAttribute.setCreateTime(DateUtil.getNowDate());
                playersAttribute.setUpdateTime(DateUtil.getNowDate());
                comPlayersAttriService.save(playersAttribute);
            } else {
                //todo 判断是否过了一天，是的话重置体力值
                if (playersAttribute.getResetStrength() == null) {
                    playersAttribute.setStrength(0);
                    playersAttribute.setResetStrength(DateUtil.getNowDate());
                    comPlayersAttriService.save(playersAttribute);
                } else {
                    Long _attributeTime = DateUtil.getOldDateAddDay(playersAttribute.getResetStrength(), 1).getTime() - DateUtil.getNowDate().getTime();
                    if (_attributeTime <= 0) {
                        playersAttribute.setStrength(0);
                        playersAttribute.setResetStrength(DateUtil.getNowDate());
                        comPlayersAttriService.save(playersAttribute);
                    }
                }

            }
            //获取一个配置
            ComSettingVo comSettingVo = comSettingService.get("1").getData();
            if (comSettingVo.equals(null)) {
                return Result.of(null, false, ResultEnum.SETTING_IS_NULL.getMessage(), ResultEnum.SETTING_IS_NULL.getCode());
            }
            ComPlayersAttriSimpleVo comPlayersAttriSimpleVo = CopyUtil.copy(playersAttribute, ComPlayersAttriSimpleVo.class);

            //获取一个体力值
            //todo 后台可配置,获取一个链上数据
            Integer _configStrength = comSettingVo.getMaxStrength(), _chainStrength = DappUtil.getChildrenCount(comUsersVo.getUserId());
            //前端的显示,输出一个不小于0的体力值
            Integer _maxStrength = _configStrength + _chainStrength;
            Integer _out = _maxStrength - Math.abs(playersAttribute.getStrength());
            comPlayersAttriSimpleVo.setCurrentStrength(_out < 0 ? 0 : _out);
            //最大值是配置的值和链上数据的值相加
            comPlayersAttriSimpleVo.setMaxStrength(_maxStrength);

            //返回前端的体力值是读取一个配置的体力值，
            map.put("playerAttribute", comPlayersAttriSimpleVo);

            //返回一个游戏配置
            map.put("gameSetting", CopyUtil.copy(comSettingVo, ComSettingSimpleVo.class));
            map.put("response", JSON.parse(response));
            return Result.of(map);
        } catch (HttpClientErrorException e) {
            redisLock.unlock(_redisKey, String.valueOf(time));
            log.error(e.toString());
            //返回 402 错误
            response = e.toString();
            map.put("active", active);
            map.put("response", response);
            return Result.of(map, false, ResultEnum.USER_VERIFICATION_ERROR.getMessage(), ResultEnum.USER_VERIFICATION_ERROR.getCode());

        }

    }

    /**
     * 获取用户信息
     *
     * @param userId
     * @return
     */
    @GetMapping("getUserInfo")
    public Result<Map> getUserInfo(@RequestParam(value = "userId") String userId) {
        Map map = new HashMap();
        ComUsersVo comUsersVo = comUsersService.findByUserId(userId);
        if (comUsersVo == null) {
            return Result.of(null, false, ResultEnum.USER_DOES_NOT_EXIST.getMessage(), ResultEnum.USER_DOES_NOT_EXIST.getCode());
        }
        map.put("gold", comUsersVo.getGold());
        map.put("diamond", comUsersVo.getDiamond());
        map.put("CNT", comUsersVo.getCnt());
        map.put("SNB", comUsersVo.getSnb());
        map.put("snbPart",comUsersVo.getSnbPart());
        map.put("address", comUsersVo.getAddress());
        return Result.of(map);
    }

    /**
     * 获取用户的snb
     *
     * @param userId
     * @return
     */
    @GetMapping("getUserSnb")
    public Result<Map> getUserSnbFunction(@RequestParam(value = "userId") String userId) {
        Map map = new HashMap();
        ComUsersVo comUsersVo = comUsersService.findByUserId(userId);
        if (comUsersVo == null) {
            return Result.of(null, false, ResultEnum.USER_DOES_NOT_EXIST.getMessage(), ResultEnum.USER_DOES_NOT_EXIST.getCode());
        }
        map.put("SNB", comUsersVo.getSnb());
        map.put("snbPart",comUsersVo.getSnbPart());
        map.put("address", comUsersVo.getAddress());
        return Result.of(map);
    }


    @PostMapping("setUserInfo")
    public Result<Map> setUserInfo(@RequestParam(value = "userId") String userId,
                                   @RequestParam(value = "cnt") Integer cnt,
                                   @RequestParam(value = "snb") Integer snb,
                                   @RequestParam(value = "gold") Integer gold,
                                   @RequestParam(value = "diamond") Integer diamond) {
        Map map = new HashMap();
        ComUsersVo comUsersVo = comUsersService.findByUserId(userId);
        if (comUsersVo == null) {
            return Result.of(null, false, ResultEnum.USER_DOES_NOT_EXIST.getMessage(), ResultEnum.USER_DOES_NOT_EXIST.getCode());
        }

        comUsersVo.setCnt(cnt);
        comUsersVo.setSnb(snb);
        comUsersVo.setGold(gold);
        comUsersVo.setDiamond(diamond);
        comUsersService.save(comUsersVo);
        map.put("gold", comUsersVo.getGold());
        map.put("diamond", comUsersVo.getDiamond());
        map.put("CNT", comUsersVo.getCnt());
        map.put("SNB", comUsersVo.getSnb());
        map.put("address", comUsersVo.getAddress());
        return Result.of(map);
    }


    //推送数据接口
    @ResponseBody
    @RequestMapping("/playback/{cid}")
    public Result<Map> pushToWeb(@PathVariable String cid, String message) {
        Map<String, Object> result = new HashMap<>();
        try {
            DappWSServer.sendInfo(message, cid);
            result.put("id", cid);
            result.put("msg", message);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.of(result);
    }
}
