package com.zksy.system.utils;

import com.zksy.common.annotation.Dict;
import com.zksy.common.annotation.Excel;
import com.zksy.common.convert.BaseCovert;
import com.zksy.common.core.domain.entity.SysDictData;
import com.zksy.common.exception.ServiceException;
import com.zksy.common.utils.StringUtil;
import com.zksy.common.utils.result.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.springframework.util.ObjectUtils;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author ：BIN.LI
 * @date ：2022/6/15 14:50
 * @description：
 */
@Slf4j
public class ExcelPoiUtil {
    public static HSSFWorkbook createExcelTemplate(String fileName, String sheetName, Class clazz, int columWith, int rowHight) {
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet(sheetName);
        sheet.createFreezePane(0, 1, 0, 1);
        sheet.setDefaultColumnWidth(columWith);
        sheet.setDefaultRowHeightInPoints(rowHight);
        // 产生表格标题行
        HSSFRow rowm = sheet.createRow(0);
        HSSFCell cellTiltle = rowm.createCell(0);
        HSSFCellStyle columnTopStyle = getColumnTopStyle(wb);//获取列头样式对象
        rowm.setHeight((short) 600);
        cellTiltle.setCellStyle(columnTopStyle);
        cellTiltle.setCellValue(sheetName);
        Field[] fields = clazz.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            String title = "";
            field.setAccessible(true);
            Excel excel = field.getAnnotation(Excel.class);
            if (!ObjectUtils.isEmpty(excel)) {
                title = excel.name();
                HSSFCell cell = rowm.createCell(i);
                cell.setCellValue(title);
                cell.setCellStyle(columnTopStyle);
            }
            Dict dict = field.getAnnotation(Dict.class);
            if (!ObjectUtils.isEmpty(dict)) {
                String dictType = dict.dictType();
                try {
                    if (!StringUtil.isBlank(dictType)) {
                        Class<? extends BaseCovert> convert = dict.convert();
                        BaseCovert baseCovert = convert.newInstance();
                        List<String> dictValue = baseCovert.getDictValue(dictType);
                        //设置下拉控制的范围
                        CellRangeAddressList regions = new CellRangeAddressList(1, 999, i, i);
                        // 生成下拉框内容
                        String[] strings = new String[dictValue.size()];
                        dictValue.toArray(strings);
                        DVConstraint constraint = DVConstraint.createExplicitListConstraint(strings);
                        // 绑定下拉框和作用区域
                        HSSFDataValidation data_validation = new HSSFDataValidation(regions, constraint);
                        // 对sheet页生效
                        sheet.addValidationData(data_validation);
                    }
                } catch (Exception e) {
                    log.error(title + ":" + dictType + "字典内容查询异常【{}】", e.getMessage(), e);
                }
            }
        }
        return wb;
    }

    /*
     * 列表首页的大title样式
     */
    private static HSSFCellStyle getColumnTopStyle(HSSFWorkbook workbook) {

        // 设置字体
        HSSFFont font = workbook.createFont();
        //设置字体大小
        font.setFontHeightInPoints((short) 12);
        //字体加粗
        font.setBold(true);
        //设置字体名字
        font.setFontName("Courier New");
        //设置样式;
        HSSFCellStyle style = workbook.createCellStyle();
        //设置底边框;
//        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        //设置底边框颜色;
        Map<String, HSSFColor> tripletHash = HSSFColor.getTripletHash();
        HSSFColor color = tripletHash.get(HSSFColor.HSSFColorPredefined.BLACK.getHexString());
        style.setBottomBorderColor(color.getIndex());
        //设置左边框;
//        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        //设置左边框颜色;
        style.setLeftBorderColor(color.getIndex());
        //设置右边框;
//        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        //设置右边框颜色;
        style.setRightBorderColor(color.getIndex());
        //设置顶边框;
//        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        //设置顶边框颜色;
        style.setTopBorderColor(color.getIndex());
        //在样式用应用设置的字体;
        style.setFont(font);
        //设置自动换行;
        style.setWrapText(true);
        //设置水平对齐的样式为居中对齐;
        style.setAlignment(HorizontalAlignment.CENTER);
        //设置垂直对齐的样式为居中对齐;
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        //设置背景颜色
//        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        HSSFColor hSSFColor = tripletHash.get(HSSFColor.HSSFColorPredefined.PALE_BLUE.getHexString());
        style.setFillForegroundColor(hSSFColor.getIndex());
        return style;
    }

    /*
     * 标题 列的样式
     */
    private static HSSFCellStyle getStyle(HSSFWorkbook workbook) {
        // 设置字体
        HSSFFont font = workbook.createFont();
        //设置字体大小
        font.setFontHeightInPoints((short) 12);
        //字体加粗
//        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        //设置字体名字
        font.setFontName("Courier New");
        //设置样式;
        HSSFCellStyle style = workbook.createCellStyle();
        //设置底边框;
//        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        //设置底边框颜色;
        Map<String, HSSFColor> tripletHash = HSSFColor.getTripletHash();
        HSSFColor color = tripletHash.get(HSSFColor.HSSFColorPredefined.BLACK.getHexString());
        //设置底边框颜色;
        style.setBottomBorderColor(color.getIndex());
        //设置左边框;
//        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        //设置左边框颜色;
        style.setLeftBorderColor(color.getIndex());
        //设置右边框;
//        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        //设置右边框颜色;
        style.setRightBorderColor(color.getIndex());
        //设置顶边框;
//        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        //设置顶边框颜色;
        style.setTopBorderColor(color.getIndex());
        //在样式用应用设置的字体;
        style.setFont(font);
        //设置自动换行;
        style.setWrapText(true);
        //设置水平对齐的样式为居中对齐;
//        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        //设置垂直对齐的样式为居中对齐;
//        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        //设置背景颜色
//        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        //设置水平对齐的样式为居中对齐;
        style.setAlignment(HorizontalAlignment.CENTER);
        //设置垂直对齐的样式为居中对齐;
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        HSSFColor hSSFColor = tripletHash.get(HSSFColor.HSSFColorPredefined.LIGHT_CORNFLOWER_BLUE.getHexString());
        style.setFillForegroundColor(hSSFColor.getIndex());
        return style;
    }

    public static boolean isRowBlank(Row row) {
        for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {
            Cell cell = row.getCell(i);
            if (cell != null && cell.getCellType() != CellType.BLANK && StringUtils.isNotBlank(getValue(cell, String.class))) {
                return false;
            }
        }
        return true;
    }


    public static <T> T getValue(Cell cell, Class<T> type) {
        Object value = null;
        if (null == cell) {
            return TypeUtil.transfer(value, type);
        }
        boolean isnumeric = false;
        switch (cell.getCellType()) {
            case BOOLEAN:
                value = cell.getBooleanCellValue();
                break;
            case ERROR:
                value = cell.getErrorCellValue();
                break;
            case NUMERIC:
                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
                    value = cell.getDateCellValue();
                } else {
                    value = cell.getNumericCellValue();
                    isnumeric = true;
                }
                break;
            case FORMULA:
                try {
                    value = String.valueOf(cell.getNumericCellValue());
                } catch (IllegalStateException e) {
                    value = String.valueOf(cell.getRichStringCellValue());
                }
                break;
            case STRING:
                value = StringUtils.isNotBlank(cell.getStringCellValue()) ? cell.getStringCellValue().trim() : "";
                break;
            default:
                break;
        }
        if (isnumeric && type.getName().equals("java.lang.String")) {
            cell.setCellType(CellType.STRING);
            value = StringUtils.isNotBlank(cell.getStringCellValue()) ? cell.getStringCellValue().trim() : "";
        }
        return TypeUtil.transfer(value, type);
    }

    public static <T> Response<List<T>> importExcel(InputStream in, Class<T> clazz) throws Exception {
        Map<String, List<SysDictData>> cache = new HashMap<>();
        Workbook workbook = WorkbookFactory.create(in);
        Sheet sheet = workbook.getSheetAt(0);
        if (sheet == null) {
            throw new ServiceException("文件sheet不存在");
        }
        // 1、 效验格式
        if (sheet.getLastRowNum() < 1) {
            throw new ServiceException("请填写信息");
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        int fixedNum = declaredFields.length;
        int cellNum = sheet.getRow(0).getLastCellNum(); // 列数
        int count = 0; // 记录行数
        if (fixedNum > cellNum) {
            throw new ServiceException("表头title格式不对");
        }
        List<T> list = new ArrayList<T>();
        List<String> titles = new ArrayList<>();
        Row title = sheet.getRow(0);
        for (int i = 0; i < cellNum; i++) {
            titles.add(getValue(title.getCell(i), String.class).replace("\n", "").replace("\r", ""));
        }
        for (Row row : sheet) {
            // 行为空就退出
            if (ExcelPoiUtil.isRowBlank(row)) {
                break;
            }
            if (count > 0) {
                T t = clazz.newInstance();
                for (int i = 0; i < cellNum; i++) {
                    String titleName = titles.get(i);
                    Cell cell = row.getCell(i);
                    for (Field field : declaredFields) {
                        field.setAccessible(true);
                        Excel excel = field.getAnnotation(Excel.class);
                        Dict dict = field.getAnnotation(Dict.class);
                        String name = excel.name();
                        if (titleName.equals(name)) {
                            if (!ObjectUtils.isEmpty(dict)) {
                                Class<? extends BaseCovert> convert = dict.convert();
                                String type = dict.dictType();
                                String format = dict.dateFormat();
                                if (!StringUtil.isBlank(type)) {
                                    List<SysDictData> dictList = cache.get(type);
                                    if (ObjectUtils.isEmpty(dictList)) {
                                        BaseCovert baseCovert = convert.newInstance();
                                        dictList = baseCovert.getDictData(type);
                                        cache.put(type, dictList);
                                    }
                                    String value = StringUtil.deNull(getValue(cell, String.class)).trim();
                                    if (titleName.indexOf("必填") > -1) {
                                        if (StringUtil.isBlank(value)) {
                                            throw new ServiceException("第【%s】行【%s】列数据不能为空!", count + 1, titleName);
                                        }
                                    }
                                    //获取字典value
                                    if (!ObjectUtils.isEmpty(dictList) && dictList.size() > 0) {
                                        for (SysDictData data : dictList) {
                                            String dictLabel = data.getDictLabel();
                                            if (dictLabel.equals(value)) {
                                                setFieldValue(field, t, data.getDictValue());
                                                break;
                                            }
                                        }
                                    }
                                }
                                String checkData = dict.checkData();
                                if (!StringUtil.isBlank(checkData)) {
                                    String value = StringUtil.deNull(getValue(cell, String.class)).trim();
                                    if (titleName.indexOf("必填") > -1) {
                                        if (StringUtil.isBlank(value)) {
                                            throw new ServiceException("第【%s】行【%s】列数据不能为空!", count + 1, titleName);
                                        }
                                    }
                                    if (!StringUtil.isBlank(value)) {
                                        BaseCovert baseCovert = convert.newInstance();
                                        Boolean res = baseCovert.checkData(checkData, value);
                                        if (!res) {
                                            throw new ServiceException("第【%s】行【%s】列数据格式不对!", count + 1, titleName);
                                        }
                                        setFieldValue(field, t, value);
                                    }
                                }
                                if (!StringUtil.isBlank(format)) {
                                    String value = StringUtil.deNull(getCellValue(cell)).trim();
                                    if (!ObjectUtils.isEmpty(value)) {
                                        System.out.println(cell.getCellStyle().getDataFormatString());
                                        try {
                                            if ("yyyy/mm;@".equals(cell.getCellStyle().getDataFormatString()) || "m/d/yy".equals(cell.getCellStyle().getDataFormatString())
                                                    || "yy/m/d".equals(cell.getCellStyle().getDataFormatString()) || "mm/dd/yy".equals(cell.getCellStyle().getDataFormatString())
                                                    || "dd-mmm-yy".equals(cell.getCellStyle().getDataFormatString()) || "yyyy/m/d".equals(cell.getCellStyle().getDataFormatString())
                                                    || "yyyy/mm/dd".equals(cell.getCellStyle().getDataFormatString()) || "yyyy/m/d;@".equals(cell.getCellStyle().getDataFormatString())) {
                                                try {
                                                    value = new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());
                                                } catch (Exception e) {
                                                    value = value.replaceAll("/", "-");
                                                }
                                            } else {
                                                value = value.replaceAll("/", "-");
                                            }
                                            BaseCovert baseCovert = convert.newInstance();
                                            Map<String, String> param = new HashMap<>();
                                            param.put("dateFormat", format);
                                            param.put("ts", value);
                                            Date date = baseCovert.convertDate(param);
                                            field.set(t, date);
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                            value = value.replaceAll("-", "/");
                                            throw new ServiceException("第【%s】行【%s】列数据【%s】格式不对!", count + 1, titleName, value);
                                        }
                                    }
                                    if (titleName.indexOf("必填") > -1) {
                                        if (StringUtil.isBlank(value)) {
                                            throw new ServiceException("第【%s】行【%s】列数据不能为空!", count + 1, titleName);
                                        }
                                    }
                                }
                            } else {
                                try {
                                    String value = StringUtil.deNull(getValue(cell, String.class)).trim();
                                    if (titleName.indexOf("必填") > -1) {
                                        if (StringUtil.isBlank(value)) {
                                            throw new ServiceException("第【%s】行【%s】列数据不能为空!", count + 1, titleName);
                                        }
                                    }
                                    setFieldValue(field, t, value);
                                } catch (Exception e) {
                                    throw new ServiceException("第【%s】行【%s】列数据格式异常【%s】!", count + 1, titleName, e.getMessage());
                                }
                            }
                            break;
                        }
                    }
                }
                list.add(t);
            }
            count++;
        }
        return Response.success(list);
    }

    public static <T> void setFieldValue(Field field, T t, String cellVlue) throws Exception {
        if (field.getType().equals(Integer.class)) {
            field.set(t, Integer.parseInt(cellVlue));
        } else if (field.getType().equals(Float.class)) {
            field.set(t, Float.parseFloat(cellVlue));
        } else if (field.getType().equals(Double.class)) {
            field.set(t, Double.parseDouble(cellVlue));
        } else if (field.getType().equals(Long.class)) {
            field.set(t, Long.parseLong(cellVlue));
        } else {
            field.set(t, cellVlue);
        }
    }

    public static String getCellValue(Cell cell) {
        String value = null;
        if (cell != null) {
            switch (cell.getCellType()) {
                case FORMULA:
                    try {
                        value = String.valueOf(cell.getNumericCellValue());
                    } catch (IllegalStateException e) {
                        value = String.valueOf(cell.getRichStringCellValue());
                    }
                    break;
                case NUMERIC:
                    value = String.valueOf(cell.getNumericCellValue());
                    break;
                case STRING:
                    value = String.valueOf(cell.getRichStringCellValue());
                    break;
            }
        }

        return value;
    }
}
