package cn.pluss.platform.util.excel;

import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.util.excel.model.RowInfo;
import lombok.Data;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.NumberToTextConverter;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Djh
 */
public class ExcelImportUtil {

    /**
     * 只统计复合单元格的实体类
     */
    @Data
    public static class RowCellRangeAdress {

        private Map<Integer, CellRangeAddress> cellMap = new HashMap<>();

        private int startRow;

        private int lastRow;

        public void put(Integer index, CellRangeAddress cellAddresses) {
            cellMap.put(index, cellAddresses);
        }

        public CellRangeAddress get(Integer index) {
            return cellMap.get(index);
        }
    }

    public static <T> List<T> readExcel(MultipartFile file, RowInfoGetter<T> rowInfo, int dataStartRow) throws MsgException, IOException {
        System.out.println(file.getOriginalFilename());
        Workbook workbook;
        try {
            workbook = new HSSFWorkbook(file.getInputStream());
            return dealWorkbook(workbook, rowInfo, dataStartRow);
        } catch (OfficeXmlFileException e) {
            workbook = new XSSFWorkbook(file.getInputStream());
            return dealWorkbook(workbook, rowInfo, dataStartRow);
        }
    }

    private static <T> List<T> dealWorkbook(Workbook workbook, RowInfoGetter<T> rowInfoGetter, int dataStartRow) throws MsgException {
        List<T> result = new ArrayList<>();

        int number = workbook.getNumberOfSheets();
        if (number == 0) {
            throw new MsgException("没有数据");
        }

        Sheet sheet = workbook.getSheetAt(0);
        RowInfo rowInfo = new RowInfo();
        rowInfo.startRow = dataStartRow;
        rowInfo.sheet = sheet;

        int lastRow = sheet.getLastRowNum();
        Map<Integer, RowCellRangeAdress> mergedRegionSort = getMergedRegionSort(sheet);


        int count = 0;
        T entity;

        while (rowInfo.startRow <= lastRow) {
            // 对一条数据进行处理
            RowCellRangeAdress row = mergedRegionSort.get(rowInfo.startRow);
            if (row != null) {
                rowInfo.endRow = row.getLastRow();
                entity = rowInfoGetter.getEntity(rowInfo, count);
                rowInfo.startRow = row.getLastRow() + 1;
            } else {
                rowInfo.endRow = rowInfo.startRow;
                entity = rowInfoGetter.getEntity(rowInfo, count);
                rowInfo.startRow++;
            }

            if (entity != null) {
                result.add(entity);
            }

            count++;
        }

        return result;
    }

    /**
     * 给合并的单元格进行行列分组
     */
    private static Map<Integer, RowCellRangeAdress> getMergedRegionSort(Sheet sheet) {
        Map<Integer, RowCellRangeAdress> result = new HashMap<>();
        List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();

        for (CellRangeAddress cellAddresses: mergedRegions) {
            int firstRow = cellAddresses.getFirstRow();
            int firstColumn = cellAddresses.getFirstColumn();
            int lastRow = cellAddresses.getLastRow();

            RowCellRangeAdress row = result.computeIfAbsent(firstRow, k -> new RowCellRangeAdress());
            row.put(firstColumn, cellAddresses);
            row.setStartRow(firstRow);
            if (row.getLastRow() < lastRow) {
                row.setLastRow(lastRow);
            }
        }

        return result;
    }

    /**
     * 读取cell里面的数据
     * @param cell cell对象
     * @return  单元格中的内容
     */
    public static Object readCell(Cell cell) {
        Object obj = null;
        if(cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case BOOLEAN:
                obj = cell.getBooleanCellValue();
                break;
            case ERROR:
                obj = cell.getErrorCellValue();
                break;
            case FORMULA:
                try {
                    obj = String.valueOf(cell.getNumericCellValue());
                } catch (IllegalStateException e) {
                    obj = String.valueOf(cell.getRichStringCellValue());
                }
                break;
            case NUMERIC:
                obj = NumberToTextConverter.toText(cell.getNumericCellValue());
                break;
            case STRING:
                obj = cell.getStringCellValue();
                break;
            default:
                break;
        }

        if (obj == null) {
            obj = "";
        }
        return obj;
    }

    public static boolean isEmpty(Cell cell) {
        return StringUtils.isEmpty(readCell(cell));
    }
}