package com.dxhy.core.job.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dxhy.common.constant.DbConstant;
import com.dxhy.common.datasource.config.DynamicContextHolder;
import com.dxhy.core.job.dao.TDxHttpLogJobDao;
import com.dxhy.core.job.dao.TDxViolationRecordDao;
import com.dxhy.core.job.entity.SysDept;
import com.dxhy.core.job.entity.TDxHttpLog;
import com.dxhy.core.job.entity.TDxViolationLog;
import com.dxhy.core.job.entity.TDxViolationRecord;
import com.dxhy.core.job.pojo.*;
import com.dxhy.core.job.service.ViolationLogService;
import com.dxhy.core.job.service.ViolationRecordService;
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.stereotype.Service;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author user
 */
@Service
@Slf4j
public class ViolationRecordServiceImpl extends ServiceImpl<TDxViolationRecordDao, TDxViolationRecord>
    implements ViolationRecordService {
    @Value("${jxjk.collectUrl}")
    private String collect_url;
    @Value("${jxjk.applyViolation}")
    private String applyViolation;
    @Value("${jxjk.violationResult}")
    private String violationResult;
    @Value("${jxjk.enterpriseCode}")
    private String enterpriseCode;
    @Value("${jxjk.version}")
    private String version;
    @Value("${jxjk.appId}")
    private String appId;
    @Autowired
    private TDxHttpLogJobDao tDxHttpLogDao;
    @Autowired
    private ViolationLogService violationLogService;

    @Override
    public void sendViolationRequest(String gfTaxNo, List<String> xfTaxNoList) {
        DynamicContextHolder.push(DbConstant.BASICS_READ);// 切换数据源
        SysDept sysDept = this.baseMapper.selectDeptIdAndKey(gfTaxNo);
        if (sysDept != null) {
            DynamicContextHolder.push(sysDept.getDbName() + DbConstant.BUSINESS_READ);// 切换数据源
            // 请求通用头
            GlobalInfo globalInfo = new GlobalInfo();
            // 请求通用
            Authorize authorize = new Authorize();
            // 具体参数
            TaxViolationData violationData = new TaxViolationData();
            BaseQueJson bqj = new BaseQueJson();
            int totalRow = 0;
            int addRow = 0;

            log.info("----------封装参数-------");
            try {
                // 封装参数
                globalInfo.setAppId(appId);
                globalInfo.setVersion(version);
                String ExchangeId = getDataExchangeId();
                globalInfo.setDataExchangeId(ExchangeId);
                globalInfo.setInterfaceCode(applyViolation);
                globalInfo.setEnterpriseCode(enterpriseCode);
                authorize.setAppSecId(sysDept.getAceId());
                violationData.setBuyerTaxNo(gfTaxNo);
                // 随机生成32位批次号
                String batchNo = getBatchNo();
                violationData.setBatchNo(batchNo);
                List<Map<String, String>> mapList = new ArrayList<>();
                for (String taxno : xfTaxNoList) {
                    Map<String, String> map = new HashMap<>();
                    map.put("salerTaxNo", taxno);
                    mapList.add(map);
                }
                violationData.setSalerTaxNoList(mapList);
                String dataStr = JSONObject.toJSONString(violationData);
                String base64Data = Base64.encodeBase64String(dataStr.getBytes("utf-8"));
                String appSec =
                    makeAppSec(base64Data, ExchangeId, applyViolation, sysDept.getAceId(), sysDept.getAceKey());
                authorize.setAppSec(appSec);
                bqj.setData(base64Data);
                bqj.setAuthorize(authorize);
                bqj.setGlobalInfo(globalInfo);
                String violationDataStr = JSONObject.toJSONString(bqj);
                log.info("url:" + applyViolation);
                log.info("请求参数：" + violationDataStr.toString());
                log.info("------------------------发送请求-----------------");
                // 保存请求记录
                TDxHttpLog httpLog = new TDxHttpLog();
                httpLog.setTaxno(gfTaxNo);
                httpLog.setType("55");
                httpLog.setReqText(violationDataStr.toString());
                // 得到返回报文，解析拿出返回的数量，累加用于判断数量
                httpLog.setReqDate(new Date());
                String responseJson = HttpUtil.post(collect_url, violationDataStr, 60000);
                log.info("返回报文：" + responseJson);
                httpLog.setResDate(new Date());
                // 根据发票类型保存不同实体
                BaseResJson gatherData = (BaseResJson)JSONObject.parseObject(responseJson, BaseResJson.class);
                ReturnStateInfo returnStateInfo = gatherData.getReturnStateInfo();
                String returnCode = returnStateInfo.getReturnCode();
                httpLog.setResText(responseJson);
                httpLog.setStatus("0");
                if ("0000".equals(gatherData.getReturnStateInfo().getReturnCode())) {
                    List<TDxViolationRecord> list = new ArrayList<>();
                    for (String taxno : xfTaxNoList) {
                        TDxViolationRecord violationRecord = new TDxViolationRecord();
                        violationRecord.setGfTaxNo(gfTaxNo);
                        violationRecord.setXfTaxNo(taxno);
                        violationRecord.setBatchNo(batchNo);
                        violationRecord.setResultStatus("N");
                        violationRecord.setAceId(sysDept.getAceId());
                        violationRecord.setAceKey(sysDept.getAceKey());
                        violationRecord.setCreateDate(new Date());
                        list.add(violationRecord);
                    }
                    DynamicContextHolder.push(sysDept.getDbName() + DbConstant.BUSINESS_WRITE);// 切换数据源
                    this.saveBatch(list);
                    tDxHttpLogDao.insert(httpLog);
                }
            } catch (Exception e) {
                e.printStackTrace();

            }
        }

    }

    @Override
    public void getViolationResult() {
        log.info("---------------进入违规信息获取执行方法--------------");
        BatchData batchData = new BatchData();// 批次号类
        try {
            String dataExchangeId = getDataExchangeId();// 流水号
            DynamicContextHolder.push("business" + DbConstant.BUSINESS_READ);
            List<TDxViolationRecord> list = this.baseMapper.selectRecordNoResult();// 查询认证申请记录表中状态为N的批次号
            if (list != null && list.size() > 0) {
                for (int i = 0; i < list.size(); i++) {
                    String batchNo = list.get(i).getBatchNo();
                    // 请求数据加密
                    batchData.setBatchNo(batchNo);
                    String dataStr = JSONObject.toJSONString(batchData);
                    String base64Data =
                        org.apache.commons.codec.binary.Base64.encodeBase64String(dataStr.getBytes("utf-8"));
                    // 加密串生成
                    String appSec = makeAppSec(base64Data, dataExchangeId, violationResult, list.get(i).getAceId(),
                        list.get(i).getAceKey());
                    log.info("本地请求生成加密串=======" + appSec);
                    // 请求报文拼接
                    String requstData =
                        requestData(appSec, dataExchangeId, base64Data, violationResult, list.get(i).getAceId());
                    log.info("认证结果获取请求报文为=======" + requstData);
                    // 发送请求返回请求报文
                    String responseJson = HttpUtil.post(collect_url, requstData, 60000);
                    log.info("响应请求数据为=" + responseJson);
                    try {
                        if (responseJson != null) {
                            // 将返回报文转换成实体
                            ResponesJson gatherData =
                                (ResponesJson)JSONObject.parseObject(responseJson, ResponesJson.class);
                            ReturnStateInfo ReturnStateInfo = gatherData.getReturnStateInfo();
                            if ("0000".equals(ReturnStateInfo.getReturnCode())) {
                                String data = gatherData.getData();
                                JSONObject dataJosn =
                                    JSONObject.parseObject(new String(Base64.decodeBase64(data), "UTF-8"));
                                if ("Y".equals(dataJosn.getString("batchState"))) {
                                    List<ViolationResult> datalist = JSONArray
                                        .parseArray(dataJosn.getString("violationTaxno"), ViolationResult.class);
                                    List<TDxViolationLog> violationLogs = new ArrayList<>();
                                    List<String> xfList = new ArrayList<>();
                                    for (int k = 0; k < datalist.size(); k++) {
                                        SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd");
                                        ViolationResult result = datalist.get(k);
                                        if ("4".equals(result.getStatus()) && "1".equals(result.getIsViolations())) {
                                            List<ViolationData> dataList = result.getViolations();
                                            for (ViolationData violationData : dataList) {
                                                if (!xfList.contains(result.getSalerTaxNo())) {
                                                    xfList.add(result.getSalerTaxNo());
                                                }
                                                TDxViolationLog violationLog = new TDxViolationLog();
                                                violationLog.setXfTaxNo(result.getSalerTaxNo());
                                                violationLog.setBreakLawMethod(violationData.getBreakLawMethod());
                                                violationLog.setBreakLawType(violationData.getBreakLawType());
                                                violationLog.setCreateDate(new Date());
                                                violationLog.setInputDate(violationData.getInputDate());
                                                violationLog.setPenalizeDate(violationData.getPenalizeDate());
                                                violationLogs.add(violationLog);
                                            }
                                        }
                                    }
                                    if (violationLogs.size() > 0) {
                                        DynamicContextHolder.push("business" + DbConstant.BUSINESS_WRITE);
                                        //先删除在添加
                                        violationLogService.remove(new QueryWrapper<TDxViolationLog>().eq("xf_tax_no", violationLogs.get(0).getXfTaxNo()));
                                        violationLogService.saveBatch(violationLogs);
                                    }
                                    TDxViolationRecord violationRecord = new TDxViolationRecord();
                                    violationRecord.setResultStatus("Y");
                                    violationRecord.setUpdateDate(new Date());
                                    QueryWrapper<TDxViolationRecord> queryWrapper = new QueryWrapper<>();
                                    queryWrapper.eq("batch_no", batchNo);
                                    DynamicContextHolder.push("business" + DbConstant.BUSINESS_WRITE);
                                    this.update(violationRecord, queryWrapper);
                                    if (xfList != null && xfList.size() > 0) {
                                        this.baseMapper.updateRecordValid(xfList);
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

            } else {
                log.info("--------数据库没有未返回违规信息结果的记录--------------");
            }
        } catch (Exception e) {
            log.info("---------------违规信息结果获取执行失败--------------");
            e.printStackTrace();
        }
    }

    public String requestData(String appSec, String dataExchangeId, String base64Data, String interfaceCode,
        String aceId) {
        String requstData = null;
        try {
            Authorize authorize = new Authorize();
            GlobalInfo globalInfo = new GlobalInfo();
            PeriodRequestData periodRequestData = new PeriodRequestData();
            authorize.setAppSecId(aceId);
            authorize.setAppSec(appSec);
            periodRequestData.setAuthorize(authorize);
            globalInfo.setAppId(appId);
            globalInfo.setDataExchangeId(dataExchangeId);
            globalInfo.setEnterpriseCode(enterpriseCode);
            globalInfo.setInterfaceCode(interfaceCode);
            globalInfo.setVersion(version);
            periodRequestData.setGlobalInfo(globalInfo);
            periodRequestData.setData(base64Data);
            requstData = JSONObject.toJSONString(periodRequestData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return requstData;
    }

    /**
     * 获取时间戳
     *
     * @return String
     */
    public String getDataExchangeId() {
        // enterpriseCode+8 位日期
        // (YYYYMMDD)+9 位序列号
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        StringBuilder sb = new StringBuilder();
        Random rand = new Random();
        for (int i = 0; i < 9; i++) {
            sb.append(rand.nextInt(10));
        }
        String data = sb.toString();
        String DataExchangeId = enterpriseCode + simpleDateFormat.format(new Date()) + data;
        return DataExchangeId;
    }

    /**
     * 获取批次号
     */
    public String getBatchNo() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        String date = simpleDateFormat.format(new Date());
        StringBuilder sb = new StringBuilder();
        Random rand = new Random();
        for (int i = 0; i < 24; i++) {
            sb.append(rand.nextInt(10));
        }
        String data = sb.toString();
        String batchNo = date + data;
        return batchNo;
    }

    /**
     * 加密方法
     */
    public String makeAppSec(String data, String dataExchangeId, String interfaceCode, String aceId, String aceKey) {
        String srcStr =
            "POST/rest/invoice/dii?authorize={\"appSecId\":\"" + aceId + "\"}&globalInfo={\"appId\":\"" + appId
                + "\",\"version\":\"" + version + "\",\"interfaceCode\":\"" + interfaceCode + "\",\"enterpriseCode\":\""
                + enterpriseCode + "\",\"dataExchangeId\":\"" + dataExchangeId + "\"}&" + "data=" + data + "";
        log.info("待加密的请求：" + srcStr);
        SecretKeySpec keySpec = null;
        try {
            keySpec = new SecretKeySpec(aceKey.getBytes("UTF-8"), "HmacSHA1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        Mac mac = null;
        try {
            mac = Mac.getInstance("HmacSHA1");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        try {
            mac.init(keySpec);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        byte[] singBytes = new byte[0];
        try {
            singBytes = mac.doFinal(srcStr.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String appSec = Base64.encodeBase64String(singBytes);
        log.info("---------interfaceCode接口生成的加密串=appSec--------------");
        return appSec;
    }
}
