package com.zcxk.core.utils.export;

import com.zcxk.core.utils.DateUtil;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Andy
 * @description: csv文件导出
 * @date 2021/7/16
 * @version V1.0
 **/
public class CsvExportUtil {

    /**
     * CSV文件列分隔符
     */
    private static final String CSV_COLUMN_SEPARATOR = ",";


    /**
     * @param dataList     集合数据
     * @param csvConverter 表结构数据
     * @param fileName     文件名
     */
    public static <T> File doExport(List<T> dataList, CsvConverter csvConverter, String fileName) {
        File csvFile = null;
        BufferedWriter csvWriter = null;

        try {
            // 定义文件格式并创建
            fileName = fileName + ".csv";
            csvFile = new File(fileName);

            // UTF-8使正确读取分隔符“,”
            csvWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(csvFile), "UTF-8"), 1024);

            //加上bom头，才不会中文乱码
            csvWriter.write(new String(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}));
            // 保证线程安全
            StringBuffer buf = new StringBuffer();

            // 组装表头
            for (CsvConverter.CsvEntry entry : csvConverter.getEntries()) {
                buf.append(entry.getCellName()).append(CSV_COLUMN_SEPARATOR);
            }
            csvWriter.write(buf.toString());
            csvWriter.newLine();


            // 组装数据
            if (dataList != null && dataList.size() > 0) {
                for (T data : dataList) {
                    buf = new StringBuffer();
                    Map<String, Object> map = entityToMap(data);

                    for (CsvConverter.CsvEntry fieldEntry : csvConverter.getEntries()) {
                        String fieldName = fieldEntry.getFieldName();
                        Object value = map.get(fieldName);

                        if (CsvConverter.CsvEnum.FORMATTER.equals(fieldEntry.getType())) {
                            if (value instanceof Date) {
                                buf.append(DateUtil.formatDate((Date) value, DateUtil.YYYYMMDDHHMMSS)).append("\t").append(CSV_COLUMN_SEPARATOR);
                            } else {
                                if(value != null){
                                    buf.append(value).append("\t");
                                }
                                buf.append(CSV_COLUMN_SEPARATOR);
                            }
                            continue;
                        }
                        if (value != null) {
                            String fieldValue = value.toString().trim();
                            //先判断字符里是否含有逗号
                            if (fieldValue.contains(",")) {
                                //如果还有双引号，先将双引号转义，避免两边加了双引号后转义错误
                                if (fieldValue.contains("\"")) {
                                    fieldValue = fieldValue.replace("\"", "\"\"");
                                }
                                //将逗号转义
                                fieldValue = "\"" + fieldValue + "\"";
                            }

                            buf.append(fieldValue).append("\t");
                        }
                        buf.append(CSV_COLUMN_SEPARATOR);
                    }
                    csvWriter.write(buf.toString());
                    csvWriter.newLine();
                }
            }
            csvWriter.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                csvWriter.close();
            } catch (Exception e) {
            }
        }
        return csvFile;

    }

    public static Map<String, Object> entityToMap(Object object) {
        Map<String, Object> map = new HashMap();
        for (Field field : object.getClass().getDeclaredFields()) {
            try {
                boolean flag = field.isAccessible();
                field.setAccessible(true);
                Object o = field.get(object);
                map.put(field.getName(), o);
                field.setAccessible(flag);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return map;
    }

}
