package com.jeequan.jeepay.thirdparty.device.speaker.lklsSpeaker;

import cn.com.sand.hmpay.util.StringUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.icbc.api.internal.apache.http.impl.cookie.S;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.device.ISpeakerService;
import com.jeequan.jeepay.core.model.QRCodeParams;
import com.jeequan.jeepay.core.model.device.BsjParams;
import com.jeequan.jeepay.core.model.device.LklsParams;
import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device;
import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.service.impl.*;
import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit;
import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod;
import com.jeequan.jeepay.thirdparty.device.speaker.lklsSpeaker.model.LklsBizSpeaker;
import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/*
* 云喇叭厂商： 拉卡拉
* @author cystal
* @date 2023/12/28 11:10
*/
@Slf4j
@Service
public class LklsSpeakerService implements ISpeakerService {

    /**
     * 推送接口域名
     */
    public static final String API_REQ_DOMAIN = "https://iot.yunmazhineng.com";

    /**
     * 推送播报语音接口地址
     */
    public static final String SEND_URL = "/api/ym/iot/api/sendVoiceMsg";

    /**
     * 绑定成功消息推送
     */
    public static final String BIND_SUCCESS_URL = "/api/notify/bind";

    /**
     * 拉卡拉版本绑定的地址
     */
    public static final String lkl_VERSION_BIND_URL = "/api/v2/iot/cloud/device/activate";

    /**
     * 获取营销区域广告坐标的信息
     */
    public static final String GET_BOX_MARKET_AREA_ADVERT = "/syapi/ym/marketArea/findCoordinateInfo";


    /**
     * 获取营销区域图片的信息
     */
    public static final String GET_BOX_MARKET_PIC_ADVERT = "/syapi/ym/marketArea/findMarketPic";

    /**
     * 设置营销区域的图片
     */
    public static final String SET_BOX_MARKET_PIC_ADVERT = "/syapi/ym/marketArea/setMarketPic";


    /**
     * 设备最新投放结果
     */
    public static final String PREVIEW_BOX_MARKET_RESULT_ADVERT = "/syapi/ym/marketArea/findLaunchStatus";


    /**
     * 批量查询最新投放结果
     */
    public static final String PREVIEW_BATCH_BOX_MARKET_RESULT_ADVERT = "/syapi/ym/marketArea/batchfindLaunchStatus";


    /**
     * 查询活动码信息
     */
    public static final String GET_BOX_ACTIVITY_INFO = "/syapi/ym/marketArea/findByActivityMsg";


    /**
     * 设置设备跑马灯
     */
    public static final String SET_BOX_MARQUEE_INFO_ADVERT = "/syapi/ym/marketArea/setMarqueeInfo";


    /**
     * 获取设备跑马灯
     */
    public static final String GET_BOX_MARQUEE_INFO_ADVERT = "/syapi/ym/marketArea/findMarqueeInfo";

    /**
     * 获取设备收款码区域坐标
     */
    public static final String GET_BOX_PAY_CODE_INFO_ADVERT = "/syapi/ym/marketArea/findPayCodeInfo";

    /**
     * 设置收款码区域图片信息
     */
    public static final String SET_BOX_PAY_CODE_PIC_ADVERT = "/syapi/ym/marketArea/setPayCodePic";


    /**
     * 获取收款码区域图片信息
     */
    public static final String GET_BOX_PAY_CODE_PIC_ADVERT = "/syapi/ym/marketArea/findPayCodePic";


    /**
     * 获取设备支付后营销区域坐标
     */
    public static final String GET_BOX_PAY_RET_INFO_ADVERT = "/syapi/ym/marketArea/findPayRetInfo";


    /**
     * 设置支付后营销区域图片信息
     */
    public static final String SET_BOX_PAY_RET_INFO_ADVERT = "/syapi/ym/marketArea/setPayRetPic";


    /**
     * 获取支付后营销区域图片信息
     */
    public static final String GET_BOX_PAY_RET_PIC_ADVERT = "/syapi/ym/marketArea/findPayRetPic";


    @Autowired private DeviceProvideConfigService deviceProvideConfigService;

    @Autowired private MchStoreDeviceService mchStoreDeviceService;

    @Autowired private SysConfigService sysConfigService;

    @Autowired private MchStoreService mchStoreService;

    @Autowired private MchApplymentService mchApplymentService;

    @Autowired private ConfigContextQueryService configContextQueryService;

    @Override
    public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException {
        sendCustomMsg(deviceParams, payOrderInfo);
    }

    @Override
    public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        JSONObject bizData = LklsUtil.getSpeakData(lklsParams, payOrderInfo);
        String respBizData = LklsUtil.req(API_REQ_DOMAIN + SEND_URL,lklsParams, bizData);
    }

    /**
     * 绑定成功消息推送
     * @param deviceParams
     * @param isVersion false 自收单版本 true 默认拉卡拉收单版本
     * @return
     */
    @Override
    public void bindSend(JSONObject deviceParams,boolean isVersion) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        if(isVersion){
            MchStore store = mchStoreService.getById(lklsParams.getExtParams().getStoreId());
            if(store == null || StringUtils.isEmpty(store.getMchApplyId())){
                throw new BizException("门店信息异常或门店关联的商户信息异常");
            }
            MchApplyment applyment = mchApplymentService.getById(store.getMchApplyId());
            if(applyment == null){
                throw new BizException("商户信息异常");
            }
            if(MchApplyment.STATE_SUCCESS != applyment.getState()){
                throw new BizException("门店关联的商户信息还未入网完成");
            }
            LklspayIsvParams isvParams = (LklspayIsvParams)configContextQueryService.queryIsvParams(applyment.getIsvNo(), applyment.getIfCode());
            JSONObject reqData = new JSONObject();
            reqData.put("merId",applyment.getChannelMchNo());
            JSONObject bizData = JSONObject.parseObject(applyment.getSuccResParameter());
            reqData.put("termId",bizData.getString("termNo"));
            reqData.put("sn",lklsParams.getDeviceParams().getDeviceNo());
            reqData.put("businessType","1");
            reqData.put("shopName",store.getStoreName());
            reqData.put("source","LOAP");
            reqData.put("merOrgNo","964645");
//            String result = LklspayKit.reqMch(LklPayMethod.Api.DEVICE_SPEAKER_BOX_ACTIVATE_URL, isvParams, reqData);
//            return result;
        }else{
            JSONObject bizData = new JSONObject(4);
            bizData.put("deviceSn",lklsParams.getDeviceParams().getDeviceNo());
            bizData.put("binding",lklsParams.getExtParams().getBindState());
            String result = LklsUtil.req(API_REQ_DOMAIN + BIND_SUCCESS_URL,lklsParams, bizData);
//            return JSON.parseObject(result);
        }
    }

    private LklsParams getLklsParams(JSONObject deviceParams) {
        JSONObject data = new JSONObject();
        data.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams")));
        data.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams")));
        data.put("extParams", JSON.parseObject(deviceParams.getString("extParams")));
        return JSON.parseObject(data.toJSONString(), LklsParams.class);
    }

    /**
     * 设备绑定查询
     * @param params
     * @return
     */
    @Override
    public JSONObject bindQuery(JSONObject params) {
        log.info("【拉卡拉音箱】绑定查询请求参数：{}",params.toString());
        DeviceProvideConfig config = deviceProvideConfigService.getOneByAppId(params.getString("appId"));
        try {
            LklsBizSpeaker bizData = preCheck(config,params);
            JSONObject bizResult = new JSONObject(8);
            MchStoreDevice deviceInfo = mchStoreDeviceService.getDeviceInfo(bizData.getDeviceSn(), config.getDeviceType(), config.getProvider());
            bizResult.put("binding",Integer.valueOf(deviceInfo.getBindState()));
            return initResult(params,HttpStatus.OK.value(), "获取成功",bizResult);
        }catch (BizException e){
            return initResult(params,ApiCodeEnum.CUSTOM_FAIL.getCode(), e.getMessage(),null);
        }
    }

    /**
     * 初始化返回信息
     * @param params
     * @param code
     * @param msg
     * @return
     */
    private JSONObject initResult(JSONObject params,Integer code ,String msg,JSONObject bizData) {
        if(bizData == null){
            bizData = new JSONObject(3);
        }
        bizData.put("code", code);
        bizData.put("msg",msg);
        params.put("reqData",Base64.encode(bizData.toString()));
        return params;
    }

    /**
     * 设备获取url
     * @param params
     * @return
     */
    @Override
    public JSONObject getUrl(JSONObject params) {
        log.info("【拉卡拉音箱】获取二维码请求参数：{}",params.toString());
        DeviceProvideConfig config = deviceProvideConfigService.getOneByAppId(params.getString("appId"));
        try {
            LklsBizSpeaker speaker = preCheck(config, params);
            MchStoreDevice mchStoreDevice = mchStoreDeviceService.getDeviceInfo(speaker.getDeviceSn(), config.getDeviceType(), config.getProvider());
            if(mchStoreDevice == null){
                log.info("设备信息未找到,参数1:{},参数2:{},参数3:{}",speaker.getDeviceSn(),config.getDeviceType(),config.getProvider());
                return initResult(params,ApiCodeEnum.SYSTEM_ERROR.getCode(),"设备信息未找到",null);
            }
            MchApplyment mchApplyment = mchApplymentService.getById(mchStoreDevice.getMchApplyId());

            JSONObject bizResult = new JSONObject();
            //如果是绑定的马牌
            String url = sysConfigService.getDBApplicationConfig().genUniJsapiPayUrl(QRCodeParams.TYPE_QRC_DEVICE, QRCodeParams.ENTRY_PAGE_LITE,mchStoreDevice.getDeviceId().toString(), mchApplyment.getIsvNo(),speaker.getAmount());
            bizResult.put("url",url);
            Integer effectTime = speaker.getAmount() != null ? 30 : -1;
            bizResult.put("effectTime",effectTime);
            return initResult(params,HttpStatus.OK.value(), "获取成功",bizResult);
        }catch (BizException e){
            return initResult(params,ApiCodeEnum.SYSTEM_ERROR.getCode(),e.getMessage(),null);
        }
    }


    private LklsBizSpeaker preCheck(DeviceProvideConfig config, JSONObject params) {
        if(config == null){
            throw new BizException("未获取音箱厂家配置信息");
        }
        String providerParams = config.getProviderParams();
        if(StringUtils.isEmpty(providerParams)){
            throw new BizException("音箱厂家基础配置信息为空");
        }
        JSONObject paramsProviderConfig = JSON.parseObject(providerParams);
        if(StringUtils.isEmpty(paramsProviderConfig.getString("appSecret"))){
            throw new BizException("音箱厂家密钥信息为空");
        }
        checkSign(params,paramsProviderConfig.getString("appSecret"));
        String reqData = params.getString("reqData");
        return JSON.parseObject(Base64.decodeStr(reqData),LklsBizSpeaker.class);
    }
    /**
     *校验参数
     */
    public void checkSign(JSONObject params, String appSecret) {
        String signType = params.getString("signType");
        String sign = params.getString("sign");
        String reqData = params.getString("reqData");
        String checkSign = null;
        if("md5".equals(signType)){
            checkSign = SecureUtil.md5(reqData + appSecret);
        }else if("HmacSHA256".equals(signType)){
            HMac hmac = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, appSecret);
            checkSign = hmac.digestHex(reqData);
        }else{
            throw new BizException("未知的签名类型");
        }
        if(!checkSign.equals(sign)){
            throw new BizException("签名异常");
        }
    }

    /**
     * 获取营销区域的广告坐标信息
     * @param deviceParams
     * @return
     */
    public JSONObject getMarketAreaAdvert(JSONObject deviceParams) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        JSONObject bizData = new JSONObject();
        bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo());
        String bizResult = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_MARKET_AREA_ADVERT, lklsParams, bizData);
        return JSON.parseObject(bizResult);
    }

    /**
     * 设置营销区域的广告
     * @param deviceParams
     * @param bizData
     * @return
     */
    public JSONObject setMarketAreaAdvert(JSONObject deviceParams,JSONObject bizData) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        String bizResult = LklsUtil.req(API_REQ_DOMAIN + SET_BOX_MARKET_PIC_ADVERT, lklsParams, bizData);
        return JSON.parseObject(bizResult);
    }

    /**
     * 获取设备跑马灯广告
     * @param deviceParams
     * @return
     */
    public JSONObject getMarqueeInfo(JSONObject deviceParams) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        JSONObject bizData = new JSONObject();
        bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo());
        bizData.put("translsNo", SeqKit.genFlowNo("F"));
        String bizResult = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_MARQUEE_INFO_ADVERT, lklsParams, bizData);
        return JSON.parseObject(bizResult);
    }

    /**
     * 设置跑马灯
     * @param deviceParams
     * @param bizData
     * @return
     */
    public JSONObject setMarqueeInfo(JSONObject deviceParams,JSONObject bizData) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        String bizResult = LklsUtil.req(API_REQ_DOMAIN + SET_BOX_MARQUEE_INFO_ADVERT, lklsParams, bizData);
        return JSON.parseObject(bizResult);
    }

    /**
     * 获取营销区域的图片信息
     * @param deviceParams
     * @return
     */
    public JSONArray getMarketPic(JSONObject deviceParams) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        JSONObject bizData = new JSONObject();
        bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo());
        String bizResult = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_MARKET_PIC_ADVERT, lklsParams, bizData);
        return JSONArray.parseArray(bizResult);
    }

    public void setMarketPic(JSONObject deviceParams, JSONObject bizData) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        LklsUtil.req(API_REQ_DOMAIN + SET_BOX_MARKET_PIC_ADVERT, lklsParams, bizData);
    }

    /**
     * 查询设备活动码信息
     * @param deviceParams
     * @return
     */
    public JSONObject getActivityQrCode(JSONObject deviceParams) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        JSONObject bizData = new JSONObject();
        bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo());
        String result = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_ACTIVITY_INFO, lklsParams, bizData);
        return JSON.parseObject(result);
    }

    /**
     * 获取设备付款区域坐标
     * @param deviceParams
     * @return
     */
    public JSONObject getMarketPayCodeInfo(JSONObject deviceParams) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        JSONObject bizData = new JSONObject();
        bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo());
        bizData.put("translsNo",SeqKit.genFlowNo("F"));
        String result = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_PAY_CODE_INFO_ADVERT, lklsParams, bizData);
        return JSON.parseObject(result);
    }

    /**
     * 获取设备付款区域图片信息
     * @param deviceParams
     * @return
     */
    public JSONObject getMarketPayCodePic(JSONObject deviceParams) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        JSONObject bizData = new JSONObject();
        bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo());
        bizData.put("translsNo",SeqKit.genFlowNo("F"));
        String result = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_PAY_CODE_PIC_ADVERT, lklsParams, bizData);
        return JSON.parseObject(result);
    }

    public void setMarketPayCodePic(JSONObject deviceParams, JSONObject bizData) {
        LklsParams lklsParams = getLklsParams(deviceParams);
        LklsUtil.req(API_REQ_DOMAIN + SET_BOX_PAY_CODE_PIC_ADVERT, lklsParams, bizData);
    }
}
