package com.yeejoin.amos.boot.biz.common.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExcelUtil {

    private static final Integer DUTY_CAR_START_INDEX = 5;

    /**
     * 生成excel模板
     *
     * @param response
     * @param fileName  下载的文件名，
     * @param sheetName sheet名
     * @param data      导出的数据
     * @param model     导出的头
     * @param flag      true模板填充下拉  false 不填充
     */
    public static void createTemplate(HttpServletResponse response, String fileName,
                                      String sheetName, List<? extends Object> data,
                                      Class<?> model, DataSources dataDictionaryMapper, boolean flag) {

        HorizontalCellStyleStrategy horizontalCellStyleStrategy = setMyCellStyle();
        try {
            //下拉列表集合
            Map<Integer, String[]> explicitListConstraintMap = new HashMap<>();
            if (flag) {
                //循环获取对应列得下拉列表信息
                Field[] declaredFields = model.getDeclaredFields();
                for (int i = 0; i < declaredFields.length; i++) {
                    Field field = declaredFields[i];
                    //解析注解信息
                    ExplicitConstraint explicitConstraint = field.getAnnotation(ExplicitConstraint.class);
                    resolveExplicitConstraint(explicitListConstraintMap, explicitConstraint, dataDictionaryMapper);
                }
            }
            EasyExcel.write(getOutputStream(fileName, response, ExcelTypeEnum.XLSX), model)
                    .excelType(ExcelTypeEnum.XLSX).sheet(sheetName)
                    .registerWriteHandler(new TemplateCellWriteHandlerDate(explicitListConstraintMap))
                    .registerWriteHandler(new TemplateCellWriteHandler())
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    .doWrite(data);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("系统异常！");

        }
    }

    /**
     * 生成excel模板
     *
     * @param response
     * @param fileName  下载的文件名，
     * @param sheetName sheet名
     * @param data      导出的数据
     * @param model     导出的头
     * @param flag      true模板填充下拉  false 不填充
     */
    public static void createDutyTemplate(HttpServletResponse response, String fileName, String sheetName, List<?
            extends Object> data, Class<?> model, List<String> dayByMonth, String[] dutyNameList,
                                          DataSources dataDictionaryMapper,
                                          boolean flag) {

        HorizontalCellStyleStrategy horizontalCellStyleStrategy = setMyCellStyle();
        try {
            // 组装表头
            List<List<String>> dutyCarTitleList = new ArrayList<>();
            Field[] declaredFields = model.getDeclaredFields();
            for (int i = 0; i < declaredFields.length; i++) {
                Field field = declaredFields[i];
                ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
                if (excelProperty != null) {
                    ArrayList<String> head = new ArrayList<>();
                    head.add(excelProperty.value()[0]);
                    dutyCarTitleList.add(head);
                }
            }
            int size = dutyCarTitleList.size();
            if (dayByMonth != null) {
                for (int i = 0; i < dayByMonth.size(); i++) {
                    ArrayList<String> dutyDay = new ArrayList<>();
                    dutyDay.add(dayByMonth.get(i));
                    dutyCarTitleList.add(dutyDay);
                }
            }
            //下拉列表集合
            Map<Integer, String[]> explicitListConstraintMap = new HashMap<>();
            if (flag) {
                // 组装下拉列表
                for (int i = 0; i < declaredFields.length; i++) {
                    Field field = declaredFields[i];
                    //解析注解信息
                    ExplicitConstraint explicitConstraint = field.getAnnotation(ExplicitConstraint.class);
                    resolveExplicitConstraint(explicitListConstraintMap, explicitConstraint, dataDictionaryMapper);
                }
                if (dayByMonth != null) {
                    for (int i = 0; i < dayByMonth.size(); i++) {
                        explicitListConstraintMap.put(size + i, dutyNameList);
                    }
                }
            }
//            String s = new String(fileName.getBytes(), "UTF-8");
//            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(s, "UTF-8"));
            ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcel.write(getOutputStream(fileName, response,
                    ExcelTypeEnum.XLSX)).head(dutyCarTitleList).excelType(ExcelTypeEnum.XLSX)
                    .sheet(sheetName).registerWriteHandler(new TemplateCellWriteHandlerDate(explicitListConstraintMap))
                    .registerWriteHandler(new TemplateCellWriteHandler())
                    .registerWriteHandler(horizontalCellStyleStrategy);
            excelWriterSheetBuilder.doWrite(data);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("系统异常！");

        }
    }

    /**
     * 读取 Excel(第一个 sheet)  指定行开始读取
     *
     * @param excel   文件
     * @param rowType 模板实体类
     * @param header  指定不读取的表头行数，
     * @param <T>
     * @return 集合数据
     * @throws Exception
     */
    public static <T> List<T> readFirstSheetExcel(MultipartFile excel, Class<T> rowType, int header) throws Exception {
        ExcelReader reader = getReader(excel, header);
        if (reader == null) {
            return new ArrayList<>();
        }
        return readExcel(reader, rowType, 0);
    }


    /**
     * 读取 Excel(多个 sheet)
     *
     * @param reader     读取的excel
     * @param rowModel   excel模板实体类
     * @param sheetCount sheet
     * @param <T>
     * @return
     */
    public static <T> List<T> readExcel(ExcelReader reader, Class<T> rowModel, int sheetCount) {
        if (reader == null) {
            return new ArrayList<>();
        }
        ExcelListener<T> excelListener = new ExcelListener<>();
        ReadSheet readSheet = EasyExcel.readSheet(sheetCount)
                .head(rowModel)
                .registerReadListener(excelListener)
                .build();
        reader.read(readSheet);
        return excelListener.getList();
    }


    /**
     * @param excel  需要解析的 Excel 文件
     * @param header 指定不读取表头行数，
     * @return
     * @throws Exception
     */
    public static ExcelReader getReader(MultipartFile excel, int header) throws Exception {
        String fileName = excel.getOriginalFilename();
        if (fileName == null) {
            throw new Exception("文件不存在！");
        }
        if (!fileName.toLowerCase().endsWith(ExcelTypeEnum.XLS.getValue()) && !fileName.toLowerCase().endsWith(ExcelTypeEnum.XLSX.getValue())) {
            throw new Exception("文件类型异常！");
        }
        InputStream inputStream;
        try {
            inputStream = excel.getInputStream();
            return EasyExcel.read(inputStream).
                    headRowNumber(header).
                    build();
        } catch (IOException e) {
            //do something
        }
        return null;
    }


    /**
     * 解析注解内容 获取下列表信息
     *
     * @param explicitConstraint
     * @return
     */
    public static Map<Integer, String[]> resolveExplicitConstraint(Map<Integer, String[]> explicitListConstraintMap,
                                                                   ExplicitConstraint explicitConstraint,
                                                                   DataSources dataDictionaryMapper) {
        if (explicitConstraint == null) {
            return null;
        }
        //固定下拉信息
        String[] source = explicitConstraint.source();
        if (source.length > 0) {
            explicitListConstraintMap.put(explicitConstraint.indexNum(), source);
        }
        //动态下拉信息
        Class<? extends ExplicitInterface>[] classes = explicitConstraint.sourceClass();
        if (classes.length > 0) {
            ExplicitInterface explicitInterface = null;
            try {
                explicitInterface = classes[0].newInstance();
                String[] source1 = explicitInterface.source(explicitConstraint.type(), explicitConstraint.method(),
                        dataDictionaryMapper);
                if (source1.length > 0) {
                    explicitListConstraintMap.put(explicitConstraint.indexNum(), source1);
                }
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * 导出文件时为Writer生成OutputStream
     */
    private static OutputStream getOutputStream(String fileName, HttpServletResponse response,
                                                ExcelTypeEnum excelTypeEnum) throws Exception {
        //创建本地文件
        String filePath = fileName + excelTypeEnum.getValue();
        try {
            fileName = new String(filePath.getBytes(), StandardCharsets.UTF_8);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setContentType("application/vnd.ms-excel");
            response.addHeader("Content-Disposition", "filename=" + fileName);
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName,
                    StandardCharsets.UTF_8.name()));
            return response.getOutputStream();
        } catch (IOException e) {
            throw new Exception("系统异常");
        }
    }

    /**
     * 创建我的cell  策略
     *
     * @return
     */
    public static HorizontalCellStyleStrategy setMyCellStyle() {

//        // 头的策略
//        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//        // 设置表头居中对齐
//        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//        // 颜色
//        headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
//        
//        WriteFont headWriteFont = new WriteFont();
//        headWriteFont.setFontHeightInPoints((short) 10);
//        // 字体
//        headWriteCellStyle.setWriteFont(headWriteFont);
//        headWriteCellStyle.setWrapped(true);    
//        // 内容的策略
//        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//        // 设置内容靠中对齐
//        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
//        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy
//        (headWriteCellStyle, contentWriteCellStyle);
//        // 这里 需要指定写用哪个class去写，然后写到第一个sheet，名字为模板 然后文件流会自动关闭   
//        return horizontalCellStyleStrategy;


        // 表头样式策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //表头前景色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setBold(true);
        headWriteFont.setFontName("宋体");
        headWriteFont.setFontHeightInPoints((short) 10);
        headWriteCellStyle.setWriteFont(headWriteFont);

        //2 内容样式策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        WriteFont contentWriteFont = new WriteFont();
        //内容字体大小
        contentWriteFont.setFontName("宋体");
        contentWriteFont.setFontHeightInPoints((short) 10);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        //设置自动换行
        contentWriteCellStyle.setWrapped(true);
        //设置垂直居中
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 头默认了 FillPatternType所以可以不指定。
        //  contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        //设置水平居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        //设置边框样式
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);

        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }
}
