package com.ruoyi.business.controller;

import cn.hutool.core.date.StopWatch;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.business.domain.FileExchangeResolve;
import com.ruoyi.business.domain.FileExchangeResolveLog;
import com.ruoyi.business.service.IDatabaseService;
import com.ruoyi.business.service.IFileExchangeResolveLogService;
import com.ruoyi.business.service.IFileExchangeResolveService;
import com.ruoyi.common.core.exception.BusinessException;
import com.ruoyi.common.core.utils.ServletUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.http.*;
import org.springframework.util.StreamUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.nio.file.Files;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.List;
import java.util.Map;

import static com.ruoyi.common.core.constant.HttpStatus.UNAUTHORIZED;
import static com.ruoyi.common.core.utils.file.FileTypeUtils.getFileType;
import static com.ruoyi.common.core.utils.file.FileUtils.getFileSize;
import static com.ruoyi.common.core.utils.file.ZipUtils.readZipFileToList;
import static com.ruoyi.common.core.web.domain.AjaxResult.success;

@Slf4j
@Validated
@RestController
@RequestMapping("/packageResolve")
@RequiredArgsConstructor
public class PackageResolveController {
    private final IFileExchangeResolveService fileExchangeResolveService;
    private final IFileExchangeResolveLogService fileExchangeResolveLogService;
    private final IDatabaseService databaseService;
    private final RestTemplate restTemplate;

//    @InnerAuth
    @GetMapping
    public AjaxResult filePackageResolve(@RequestParam("exchangeResolveId") Long id) throws Exception {
        StopWatch sw = StopWatch.create("sw");
        sw.start();
        FileExchangeResolve exchangeResolve = fileExchangeResolveService.selectFileExchangeResolveById(id);
        String url = exchangeResolve.getInterfaceUrl();
        HttpHeaders reqHeaders = new HttpHeaders();
        reqHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        String auth = ServletUtils.getHeader(HttpHeaders.AUTHORIZATION);
        if (auth == null) {
            throw new BusinessException("认证失败", UNAUTHORIZED);
        } else {
            String token = auth.substring(6).trim();
            reqHeaders.setBearerAuth(token);
        }
        HttpEntity<Object> requestEntity = new HttpEntity<>(reqHeaders);
        // 响应类型不支持InputStream类型，使用Resource或byte[]接收三方文件服务返回的文件字节流
        ResponseEntity<byte[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, byte[].class, requestEntity);
        if(ObjectUtils.isEmpty(responseEntity.getBody())) {
            throw new BusinessException("返回内容为空");
        }
        // 第三方文件服务的响应头
        HttpHeaders respHeader = responseEntity.getHeaders();
        List<String> secretList = respHeader.get("zip-secret");
        String secret;
        if(ObjectUtils.isNotEmpty(secretList)) {
            secret = secretList.get(0);
        } else {
            String s = new String(responseEntity.getBody());
            return AjaxResult.success(s);
        }

        ContentDisposition contentDisposition = respHeader.getContentDisposition();
        String filename = contentDisposition.getFilename();
        File tmpFile = new File("\\tmp\\" + filename);
        String zipName = tmpFile.getAbsolutePath();
        try {
            // 1、先保存到临时文件
            boolean mkdirs = tmpFile.getParentFile().mkdirs();
            StreamUtils.copy(responseEntity.getBody(), Files.newOutputStream(tmpFile.toPath()));
            if(!getFileType(zipName).equals(exchangeResolve.getFileType())) {
                throw new BusinessException("后缀校验错误：" + getFileType(zipName));
            }
            double fileSizeInMB = getFileSize(zipName, "MB");
            if(fileSizeInMB > exchangeResolve.getFileSize()) {
                throw new BusinessException("大小校验错误：" + fileSizeInMB + "兆>" + exchangeResolve.getFileSize() + "兆");
            }
            List<Map<String, Object>> list = readZipFileToList(zipName, secret);
            FileExchangeResolveLog exchangeResolveLog = new FileExchangeResolveLog();
            exchangeResolveLog.setParentId(exchangeResolve.getId());
            exchangeResolveLog.setInterfaceName(exchangeResolve.getInterfaceName());
            exchangeResolveLog.setInterfaceUrl(exchangeResolve.getInterfaceUrl());
            exchangeResolveLog.setResolveRule(exchangeResolve.getResolveRule());
            if(ObjectUtils.isNotEmpty(list)) {
                StringBuilder sb = new StringBuilder("insert into ");
                sb.append(exchangeResolve.getTableName());
                sb.append(" (");
                Map<String, Object> map = list.get(0);
                for (String key: map.keySet()) {
                    sb.append(key);
                    sb.append(",");
                }
                sb.deleteCharAt(sb.length() -1);
                sb.append(") VALUES (");
                for (String key: map.keySet()) {
                    sb.append("?,");
                }
                sb.deleteCharAt(sb.length() -1);
                sb.append(")");
                String sqlInsert = sb.toString();
                Connection conn = databaseService.getConnection(exchangeResolve.getDatabaseId(), null);
                PreparedStatement ps = conn.prepareStatement(sqlInsert);
                int size = list.size();
                int index;
                for (int i = 0; i < size; i++) {
                    Map<String, Object> mapData = list.get(i);
                    index = 1;
                    for (String key: map.keySet()) {
                        ps.setObject(index++, mapData.get(key));
                    }
                    ps.addBatch();//将sql语句打包到一个容器中
                    if (i % 500 == 0) {
                        ps.executeBatch();//将容器中的sql语句提交
                        ps.clearBatch();//清空容器，为下一次打包做准备
                    }
                }
                //为防止有sql语句漏提交【如i结束时%500！=0的情况】，需再次提交sql语句
                ps.executeBatch();//将容器中的sql语句提交
                ps.clearBatch();//清空容器
                ps.close();
                conn.close();
                exchangeResolveLog.setIdRange(list.get(0).get(exchangeResolve.getIdField().toLowerCase()) + "," +
                        list.get(list.size() - 1).get(exchangeResolve.getIdField().toLowerCase()));
                exchangeResolveLog.setDataNum(list.size());
            }
            sw.stop();
            exchangeResolveLog.setResolveTime(sw.getLastTaskInfo().getTimeSeconds());
            exchangeResolveLog.setDatabaseId(exchangeResolve.getDatabaseId());
            exchangeResolveLog.setDatabaseName(exchangeResolve.getDatabaseName());
            exchangeResolveLog.setTableName(exchangeResolve.getTableName());
            exchangeResolveLog.setTableRemark(exchangeResolve.getTableRemark());
            fileExchangeResolveLogService.save(exchangeResolveLog);
        } finally {
            // 3、清理临时文件和UUID目录
            if (tmpFile.exists()) {
                boolean delete = tmpFile.delete();
            }
        }
        return success();
    }
}
