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

import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.td.WaDa.annotation.Decrypt;
import com.td.WaDa.annotation.Encrypt;
import com.td.WaDa.common.controller.*;
import com.td.WaDa.common.pojo.Result;
import com.td.WaDa.game.complayerlog.service.ComPlayerLogService;
import com.td.WaDa.game.complayersattri.service.ComPlayersAttriService;
import com.td.WaDa.game.complayersattri.vo.ComPlayersAttriSimpleVo;
import com.td.WaDa.game.complayersattri.vo.ComPlayersAttriVo;
import com.td.WaDa.game.comsetting.service.ComSettingService;
import com.td.WaDa.game.comsetting.vo.ComSettingSimpleVo;
import com.td.WaDa.game.comsetting.vo.ComSettingVo;
import com.td.WaDa.game.comusers.vo.ComUsersLoginVo;
import com.td.WaDa.game.comusers.vo.ComUsersSimpleVo;
import com.td.WaDa.config.enums.ResultEnum;
import com.td.WaDa.game.comusers.pojo.ComUsers;
import com.td.WaDa.game.comusers.vo.ComUsersVo;
import com.td.WaDa.game.comusers.service.ComUsersService;
import com.td.WaDa.sys.syssetting.vo.SysSettingVo;
import com.td.WaDa.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
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.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 javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

import static com.td.WaDa.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;

    @Autowired
    private ComPlayerLogService comPlayerLogService;

    @Autowired
    private RedisSettingMap redisSettingMap;

    /**
     * 接口需要token放行
     *
     * @return
     */
    @GetMapping("RSAConfig")
    public Result<Map> publicKeyAndSys() {
        //存储在redis上
        Map map = new HashMap();
        map.put("active", active);
        map.put("publicKey", redisSettingMap.getRSAPublicKeyBase64());
        SysSettingVo sysSettingVo = redisSettingMap.getSysSettingMap();
        map.put("apiEncrypt", sysSettingVo.getSysApiEncrypt());
        return Result.of(map);
    }

    /**
     * 登录后返回一个token令牌
     *
     * @param comUsersLoginVo
     * @return
     */
    @PostMapping("login")
    @Decrypt
    @Encrypt
    public Result<Map> login(ComUsersLoginVo comUsersLoginVo) {
        log.info(comUsersLoginVo.toString());
        //DappUtil.MetaPalLogin("1","2");
        //{
        //    "uuid":"xxxxxxxxx",    // 必需
        //    "userName":"xxxx",    // 必需
        //    "realName":"xxxx",
        //    "email":"xxxxxx@xxxx.com",    // 必需
        //    "telephone":null,
        //    "birthday":null,
        //    "sex":1,                // 0女1男
        //    "accontStatus":0,            // 账号状态 0正常，1是禁止登录
        //    "wallet": “xxxxxxxx”,    // 必需
        //    "createTime":"2022.04.01-17.33.19",    // 必需
        //    "updateTime":"2022.04.01-17.33.19",    // 最新一次对账号密码或其他信息的修改时间
        //}
        String uuid = "1", address = "address1";
        Map map = new HashMap();
        String _redisKey = "SNB_SAVE_" + uuid;
        //todo snb冻结加锁
        long time = System.currentTimeMillis() + RedisData.getSnbTimeout();
        try {
            //如果校验通过，生成用户数据，生成token
            ComUsersVo comUsersVo = comUsersService.findByUserId(uuid);
            if (comUsersVo == null) {
                //如果没有用户信息
                comUsersVo = new ComUsersVo();
                comUsersVo.setUserId(uuid);
                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("userInfo", CopyUtil.copy(comUsersVo, ComUsersSimpleVo.class));
            return Result.of(map);
        } catch (HttpClientErrorException e) {
            redisLock.unlock(_redisKey, String.valueOf(time));
            log.error(e.toString());
            //返回 402 错误
            map.put("active", active);
            map.put("response", e.toString());
            return Result.of(map, false, ResultEnum.USER_VERIFICATION_ERROR.getMessage(), ResultEnum.USER_VERIFICATION_ERROR.getCode());
        }

    }

    /**
     * {
     * "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 DAppOnlineUrl = "http://192.168.20.251/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 = redisSettingMap.getComSettingMap(); //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));

            // 计算断电损耗
            comPlayerLogService.powerLoss(id);

            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());

        }

    }


    @PostMapping("loginToken")
    public Result<Map> loginToken() {
        log.info("loginToken active:" + active);
        String id = "1", address = "address1";
        Map map = new HashMap();
        String _redisKey = "SNB_SAVE_" + id;
        //todo snb冻结加锁
        long time = System.currentTimeMillis() + RedisData.getSnbTimeout();
        try {
            //如果校验通过，生成用户数据，生成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));

            return Result.of(map);
        } catch (HttpClientErrorException e) {
            redisLock.unlock(_redisKey, String.valueOf(time));
            log.error(e.toString());
            //返回 402 错误
            map.put("active", active);
            map.put("response", e.toString());
            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);
    }

}
