/*
 * Author: wangjian
 * 生成ServiceImpl
 */
package com.tofly.dc.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.tofly.common.core.entity.ResultRespone;
import com.tofly.common.core.util.JSONUtil;
import com.tofly.common.core.util.StringUtil;
import com.tofly.dc.comm.Constant;
import com.tofly.dc.comm.sys.InterfaceTypeEnum;
import com.tofly.dc.comm.sys.RunningStatusEnum;
import com.tofly.dc.entity.InterfaceLog;
import com.tofly.dc.entity.InterfaceManage;
import com.tofly.dc.exception.BusinessException;
import com.tofly.dc.service.InterfaceManageService;
import com.tofly.dc.util.DateTimeUtil;
import com.tofly.dc.util.HttpClientUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.tofly.dc.mapper.InterfaceManageMapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

/**
 * 接口管理表
 *
 * @author zev
 * @date Wed Jan 05 00:00:00 CST 2022
 */
@Service("interfaceManageService")
public class InterfaceManageServiceImpl extends ServiceImpl<InterfaceManageMapper, InterfaceManage> implements InterfaceManageService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveInfo(InterfaceManage manage) {
        // 不需要校验 接口调用识别码为接口编码 唯一
        // 生成接口编码
        String code = this.sendCode(manage);
        manage.setCode(code);
        return this.save(manage);
    }

    @Override
    public ResultRespone<Object> dispose(HttpServletRequest httpRequest, String parameter, String code, String token, InterfaceLog log,HttpServletResponse response) throws Exception {
        // 1.校验
        // 判断当前编码接口数据是否存在 是否已发布
        List<InterfaceManage> list = this.list(new QueryWrapper<InterfaceManage>().lambda()
                .eq(InterfaceManage::getCode, code)
                .eq(InterfaceManage::getRunningStatus, RunningStatusEnum.PUBLISHED.getCode())
                .eq(InterfaceManage::getDel, "0"));
        ResultRespone<Object> resultRespone = new ResultRespone<>();
        if (null != list && list.size() > 0) {
            InterfaceManage interfaceManage = list.get(0);
            log.setInterfaceId(interfaceManage.getId());
            // 2.判断接口类型
            String type = interfaceManage.getType();
            // 3.获取请求头
            Map<String, String> headersInfo = this.getHeadersInfo(httpRequest);
            String authorization = headersInfo.get("Authorization");
            // 4.获取调用url
            String url = interfaceManage.getUrl();
            // 5.获取contentType 中是否为json
            String contentType = interfaceManage.getContentType();
            boolean isJson = contentType != null && contentType.contains("2");
            // 6.根据contentType 是否包含json类型 若包含则调用 json方式
            // 7.封装不同的请求头
            Map<String, String> map = new HashMap<>(12);
            map.put("Authorization", authorization);
            if (InterfaceTypeEnum.POST.getCode().equals(type)) {
                if (isJson) {
                    resultRespone = HttpClientUtil.doPostJson(url, map, parameter);
                } else {
                    Map<String, Object> map1 = json2mapString(parameter);
                    MultiValueMap<String, MultipartFile> multiFileMap =null;
                    if (httpRequest instanceof MultipartHttpServletRequest) {
                        multiFileMap = ((MultipartHttpServletRequest)httpRequest).getMultiFileMap();
                    }
                    if (null!=multiFileMap && multiFileMap.size() > 0) {
                        multiFileMap.forEach((k, v) -> {
                            File[] fileList = new File[v.size()];
                            for (int i = 0; i < v.size(); i++) {
                                fileList[i] = convertFileByMultipartFile(v.get(i));
                            }
                            map1.put(k, fileList);
                        });
                    }

                    resultRespone = HttpClientUtil.doPost(url, map, map1);
                }
            } else if (InterfaceTypeEnum.GET.getCode().equals(type)) {
                if(contentType != null && contentType.contains("5")){
                    resultRespone = HttpClientUtil.doGetJoinId(url, map, json2mapString(parameter),response);
                }else {
                    resultRespone = HttpClientUtil.doGet(url, map, json2mapString(parameter),response);
                }

            } else if (InterfaceTypeEnum.PUT.getCode().equals(type)) {
                if (isJson) {
                    resultRespone = HttpClientUtil.doPutJson(url, map, parameter);
                } else {
                    Map<String, Object> map1 = json2mapString(parameter);
                    MultiValueMap<String, MultipartFile> multiFileMap =null;
                    if (httpRequest instanceof MultipartHttpServletRequest) {
                        multiFileMap = ((MultipartHttpServletRequest)httpRequest).getMultiFileMap();
                    }
                    if (null!=multiFileMap && multiFileMap.size() > 0) {
                        multiFileMap.forEach((k, v) -> {
                            File[] fileList = new File[v.size()];
                            for (int i = 0; i < v.size(); i++) {
                                fileList[i] = convertFileByMultipartFile(v.get(i));
                            }
                            map1.put(k, fileList);
                        });
                    }

                    resultRespone = HttpClientUtil.doPut(url, map, map1);
                }
            } else if (InterfaceTypeEnum.DELETE.getCode().equals(type)) {
                resultRespone = HttpClientUtil.doDelete(url, map, json2mapString(parameter));
            }

        } else {
            throw new BusinessException(Constant.INTERFACE_IS_NULL_OR_STOP_CODE, Constant.INTERFACE_IS_NULL_OR_STOP);
        }
        return resultRespone;
    }

    public static Map<String, Object> json2mapString(String str_json) {
        JSONObject jsonObject = JSON.parseObject(str_json);
        Map<String, Object> map = new HashMap<>(12);
        if(!jsonObject.isEmpty()){
            map = JSONUtil.reflectlinkedHashMap(jsonObject);
        }
        return map;
    }

    public static File convertFileByMultipartFile(MultipartFile file) {
        File toFile = null;
        if (file.equals("") || file.getSize() <= 0) {
            file = null;
        } else {
            InputStream ins = null;
            try {
                ins = file.getInputStream();
                toFile = new File(file.getOriginalFilename());
                inputStreamToFile(ins, toFile);
                ins.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return toFile;

    }

    //获取流文件
    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Map<String, String> getHeadersInfo(HttpServletRequest request) {
        Map<String, String> map = new HashMap<String, String>();
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        return map;
    }


    /**
     * 生成接口编码
     *
     * @param manage
     * @return
     */
    private String sendCode(InterfaceManage manage) {
        // 获取归属系统/模块编码  接口编码(归属系统+模块+YYYYMMDD+0000X序号)
        return manage.getOwnershipSystem() +
                manage.getOwnershipBusiness() +
                //生成一个序列号，每天从0开始自增
                this.produceSerialNumber();

    }

    /**
     * redis自增处理
     *
     * @return
     */
    private String produceSerialNumber() {

        //批次前缀
        String prefix = DateTimeUtil.getCurrentDate(DateTimeUtil.NUMBER_FORMAT);
        String pre = prefix.substring(0, 8);
        //使用redis生成唯一流水号
        Long sequence = stringRedisTemplate.opsForValue().increment(Constant.MESSAGE_BATCH_ROB_MAINTAIN_SEQUENCE + "_" + pre, 1);
        if (null != sequence && 1 == sequence) {
            stringRedisTemplate.delete(Objects.requireNonNull(stringRedisTemplate.keys(Constant.MESSAGE_BATCH_ROB_MAINTAIN_SEQUENCE + "_" + "*")));
            sequence = stringRedisTemplate.opsForValue().increment(Constant.MESSAGE_BATCH_ROB_MAINTAIN_SEQUENCE + "_" + pre, 1);
        }
        //批次后缀 取流水号最后5位 如果不足5位前面补0
        String suffix = String.format("%05d", sequence % 100000);
        return pre + suffix;
    }
}
