package com.keyware.shandan.browser.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.poi.excel.BigExcelWriter;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.keyware.shandan.bianmu.entity.DirectoryResource;
import com.keyware.shandan.bianmu.entity.MetadataBasicVo;
import com.keyware.shandan.bianmu.service.MetadataService;
import com.keyware.shandan.common.util.StreamUtil;
import com.keyware.shandan.common.util.StringUtils;
import com.keyware.shandan.frame.config.component.AppContext;
import com.keyware.shandan.frame.properties.CustomProperties;
import com.keyware.shandan.system.entity.SysFile;
import com.keyware.shandan.system.service.SysFileService;
import com.keyware.shandan.system.utils.SysSettingUtil;
import lombok.AllArgsConstructor;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class ExportComponent {
    private final String exportId;
    private Status status;
    private final String fileName;
    private List<DirectoryResource> dataList;
    private final CustomProperties customProperties;
    private final SysFileService fileService;
    private final MetadataService metadataService;

    public ExportComponent(String exportId) {
        this.customProperties = AppContext.getContext().getBean(CustomProperties.class);
        this.fileService = AppContext.getContext().getBean(SysFileService.class);
        this.metadataService = AppContext.getContext().getBean(MetadataService.class);
        this.exportId = exportId;
        this.status = Status.querying;
        fileName = "export_" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
    }

    /**
     * 导出文件
     *
     * @param resource 数据资源
     */
    private void exportFile(DirectoryResource resource) {
        File serverFile = new File(createResourceDir(resource.getDirectoryPath()));
        SysFile file = fileService.getById(resource.getId());
        String fileDownloadUrl = SysSettingUtil.getSysSetting("BIANMU").getSysInternalAddress() + file.getWebUri();

        try {
            HttpUtil.downloadFile(fileDownloadUrl, serverFile);
        } catch (Exception e) {
            List<String> lines = new ArrayList<>();
            lines.add("文件读取异常，请检查文件是否存在！");
            String dirPath = serverFile.getParentFile().getPath();
            String name = "(文件读取错误)" + serverFile.getName();
            FileUtil.writeLines(lines, new File(dirPath, name), "utf-8");
        }
    }

    /**
     * 导出数据表
     *
     * @param resource 数据资源
     */
    private void exportMetadata(DirectoryResource resource) {
        File serverFile = new File(createResourceDir(resource.getDirectoryPath()));
        String path = serverFile.getPath() + ".xlsx";
        MetadataBasicVo metadata = null;
        JSONArray colsArray = null;
        List<Map<String, Object>> datas = null;

        try {
            metadata = metadataService.getById(resource.getId());
            colsArray = metadataService.getColumns(metadata.getId());
            datas = metadataService.getDynamicData(metadata);
        } catch (Exception e) {
            colsArray = new JSONArray();
            JSONObject defaultJson = new JSONObject();
            // defaultJson.put("columnName", "");
            defaultJson.put("comment", "数据查询失败，无法连接到指定的数据库");
            colsArray.add(defaultJson);
            datas = new ArrayList<>();

            File temp = new File(path);
            String dirPath = temp.getParentFile().getPath();
            path = dirPath + File.separator + "(数据读取错误)" + temp.getName();
        }

        // 所有行的集合
        List<List<String>> rowList = new ArrayList<>();
        // 字段列名集合
        List<String> colNameList = new ArrayList<>();
        // 字段列名注释集合，当做表格的第一行
        List<String> columns = StreamUtil.as(colsArray).map(json -> {
            JSONObject col = (JSONObject) json;
            String comment = col.getString("comment");
            String colName = col.getString("columnName");
            String name = StringUtils.hasTextByDefault(comment, colName);
            colNameList.add(colName);
            return name;
        }).toList();

        // 添加第一行
        rowList.add(columns);

        // 遍历数据
        datas.forEach(data -> {
            // 遍历字段列名，获取对应数据并拼接成列的集合
            List<String> cells = StreamUtil.as(colNameList).map(col -> data.get(col).toString()).toList();
            rowList.add(cells);
        });

        List<List<String>> rows = CollUtil.newArrayList(rowList);
        //通过工具类创建writer
        BigExcelWriter writer = ExcelUtil.getBigWriter(path);
        //一次性写出内容
        writer.write(rows);
        //关闭writer，释放内存
        writer.close();
    }

    /**
     * 开始打包
     */
    public boolean startPackage() {
        status = Status.packaging;
        String path = getExportPath();
        try {
            dataList.forEach(resource -> {
                if ("file".equals(resource.getResourceType())) {
                    exportFile(resource);
                } else {
                    exportMetadata(resource);
                }
            });
            ZipUtil.zip(path, path + ".zip", true);
        } catch (Exception e) {
            delete(path);
            throw new RuntimeException("导出数据在打包时出错", e);
        }

        return true;
    }

    /**
     * 设置需要导出的数据
     *
     * @param dataList 数据
     */
    public void setData(List<DirectoryResource> dataList) {
        this.dataList = dataList;
    }

    public void setStatus(String status) {
        this.status = Status.valueOf(status);
    }

    public String getExportPath() {
        return customProperties.getFileStorage().getTempPath() + "/" + fileName;
    }

    /**
     * 根据资源路径创建目录
     *
     * @param resourcePath 资源路径
     * @return 资源的的绝对路径
     */
    private String createResourceDir(String resourcePath) {
        String path = getExportPath() + "/" + resourcePath;
        File file = new File(path);
        File parent = file.getParentFile();
        if (!parent.exists()) {
            parent.mkdirs();
        }
        return path;
    }

    private void delete(String path) {
        File file = new File(path);
        if(file.exists()){
            file.delete();
        }
    }

    @AllArgsConstructor
    private enum Status {
        querying("正在查询数据"),
        packaging("正在打包数据"),
        downloading("正在下载数据");

        private final String text;
    }
}
